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

#include "../include/disk.h"

#include "guiutils.h"
#include "cdialog.h"
#include "fb.h"
#include "csd.h"
#include "fsd.h"

#include "styleedit.h"

#include "images/icon_clear_20x20.xpm"


static void StyleEditCSDColorToGdkColor(
	const csd_color_struct *src_c,
	GdkColor *tar_c
);
static void StyleEditGdkColorToCSDColor(
	const GdkColor *src_c,
	csd_color_struct *tar_c
);

static void StyleEditAnyValueChangedCB(
	GtkWidget *widget, gpointer data
);
static void StyleEditStateChangeCB(
	GtkAdjustment *adj, gpointer data
);
static void StyleEditPreviousStateCB(
	GtkWidget *widget, gpointer data
);
static void StyleEditNextStateCB(
	GtkWidget *widget, gpointer data
);
static void StyleEditResetCB(
	gpointer widget, gpointer data
);
static void StyleEditBGPixmapPathCB(
	GtkWidget *widget, gpointer data
);
static gint StyleEditPreviewEventCB(
	gpointer widget, GdkEvent *event, gpointer data
);

static void StyleEditPreviewUpdate(style_edit_struct *se);
static void StyleEditPreviewDraw(style_edit_struct *se);

GtkStateType StyleEditCurrentState(style_edit_struct *se);

style_edit_struct *StyleEditNew(
	GtkWidget *parent, const gchar *name
);
void StyleEditDelete(style_edit_struct *se);
static void StyleEditSetWidgetsToStyle(
	style_edit_struct *se, GtkStateType state
);
static void StyleEditSetStyleToWidgets(
	style_edit_struct *se, GtkStateType state
);
void StyleEditSetStyle(style_edit_struct *se, const GtkRcStyle *style);
GtkRcStyle *StyleEditGetStyle(style_edit_struct *se);
static void StyleEditSetStyleFromStyle(
	style_edit_struct *se, const GtkStyle *style
);
void StyleEditRestoreDefaultStyle(style_edit_struct *se);
void StyleEditSetChangedCB(
	style_edit_struct *se,
	void (*changed_cb)(
		style_edit_struct *,
		gpointer
	),
	gpointer changed_client_data
);


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


/*
 *	Copy/converts CSD color to GdkColor.
 */
static void StyleEditCSDColorToGdkColor(
	const csd_color_struct *src_c,
	GdkColor *tar_c
)
{
	GDK_COLOR_SET_COEFF(tar_c, src_c->r, src_c->g, src_c->b)
}

/*
 *	Copy/converts GdkColor to CSD color.
 */
static void StyleEditGdkColorToCSDColor(
	const GdkColor *src_c,
	csd_color_struct *tar_c
)
{
	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);
}


/*
 *	Any value changed signal callback.
 */
static void StyleEditAnyValueChangedCB(
	GtkWidget *widget, gpointer data
)
{
	style_edit_struct *se = STYLE_EDIT(data);
	if(se == NULL)
	    return;

	if(se->freeze_count > 0)
	    return;

	se->freeze_count++;

	/* Update widget values to style */
	StyleEditSetWidgetsToStyle(
	    se,
	    StyleEditCurrentState(se)
	);

	/* Update preview style */
	StyleEditPreviewUpdate(se);

	/* Call changed callback */
	if(se->changed_cb != NULL)
	    se->changed_cb(
		se,			/* Style Edit */
		se->changed_client_data	/* Data */
	    );

	se->freeze_count--;
}

/*
 *      Style Edit state adjustment "value_changed" signal callback.
 */
static void StyleEditStateChangeCB(
	GtkAdjustment *adj, gpointer data
)
{
	GtkStateType state, prev_state;
	const gchar *s = "";
	GtkWidget *w;
	GtkRcStyle *style;
	style_edit_struct *se = STYLE_EDIT(data);
	if(se == NULL)
	    return;

	style = se->style;
	prev_state = se->prev_state;
	state = StyleEditCurrentState(se);

	/* Change in state? */
	if(prev_state != state)
	{
	    StyleEditSetWidgetsToStyle(se, prev_state);
	    StyleEditSetStyleToWidgets(se, state);
	    StyleEditPreviewDraw(se);
	    se->prev_state = state;
	}

	/* Update state entry */
	w = se->state_entry;
	switch(state)
	{
	  case GTK_STATE_NORMAL:
	    s = "Normal";
	    break;
	  case GTK_STATE_ACTIVE:
	    s = "Active";
	    break;
	  case GTK_STATE_PRELIGHT:
	    s = "Prelight";
	    break;
	  case GTK_STATE_SELECTED:
	    s = "Selected";
	    break;
	  case GTK_STATE_INSENSITIVE:
	    s = "Insensitive";
	    break;
	}
	gtk_entry_set_text(GTK_ENTRY(w), s);
	gtk_entry_set_position(GTK_ENTRY(w), -1);

#if 0
	/* Update button sensitivity */
	GTK_WIDGET_SET_SENSITIVE(
	    se->state_previous_btn,
	    (state > 0) ? TRUE : FALSE
	)
	GTK_WIDGET_SET_SENSITIVE(
	    se->state_next_btn,
	    (state < (STYLE_EDIT_STATES - 1)) ? TRUE : FALSE
	)
#endif
}

/*
 *      Style Edit previous state callback.
 */
static void StyleEditPreviousStateCB(
	GtkWidget *widget, gpointer data
)
{
	GtkAdjustment *adj;
	style_edit_struct *se = STYLE_EDIT(data);
	if(se == NULL)
	    return;

	adj = se->state_adj;
	gtk_adjustment_set_value(
	    adj,
	    MAX(
		adj->value - adj->step_increment,
		adj->lower
	    )
	);
}

/*
 *      Style Edit next state callback.
 */
static void StyleEditNextStateCB(
	GtkWidget *widget, gpointer data
)
{
	GtkAdjustment *adj;
	style_edit_struct *se = STYLE_EDIT(data);
	if(se == NULL)
	    return;

	adj = se->state_adj;
	gtk_adjustment_set_value(
	    adj,
	    MIN(
		adj->value + adj->step_increment,
		adj->upper - adj->page_size
	    )
	);
}

/*
 *	Style Edit reset callback.
 */
static void StyleEditResetCB(
	gpointer widget, gpointer data
)
{
	gint response;
	GtkWidget *toplevel;
	style_edit_struct *se = STYLE_EDIT(data);
	if(se == NULL)
	    return;

	toplevel = gtk_widget_get_toplevel(se->toplevel);

	CDialogSetTransientFor(toplevel);
	response = CDialogGetResponse(
#if defined(PROG_LANGUAGE_SPANISH)
"Confirme Reponga",
"¿Usted está seguro que usted quiere reponer los valores del\n\
estilo a los valores del estilo de la rebeldía de GTK?\n",
#elif defined(PROG_LANGUAGE_FRENCH)
"Confirmer Remet à L'état Initial",
"Etes-vous sûr que vous voulez remettre à l'état initial les\n\
valeurs de style au GTK les valeurs de style implicites?\n",
#elif defined(PROG_LANGUAGE_GERMAN)
"Bestätigen Sie Nachstellung",
"Sind sie sicher sie den stil werte zum GTK standardwert stil\n\
werten wollen nachstellen?\n",
#elif defined(PROG_LANGUAGE_ITALIAN)
"Confermare Il Ripristino",
"Lei sono sicuro che lei vuole ripristinare i valori di stile\n\
al GTK i valori di stile predefiniti?\n",
#elif defined(PROG_LANGUAGE_DUTCH)
"Bevestiig Reset",
"Waardeert u zeker u de stijl te de GTK Standaardstijl bent,\n\
wil resetten waardeert?\n",
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Confirme Reset",
"Estão seguro quer a reset o estilo estima aos valores de\n\
estilo de omissão de GTK?\n",
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Bekreft Tilbakestilling",
"Er De sikker De tilbakestiller stilverdiene til GTK\n\
standardverdistilverdier?\n",
#else
"Confirm Reset",
"Are you sure you want to reset the style values to\n\
the GTK default style values?\n",
#endif
	    NULL,
	    CDIALOG_ICON_QUESTION,
	    CDIALOG_BTNFLAG_YES | CDIALOG_BTNFLAG_NO,
	    CDIALOG_BTNFLAG_YES
	);
	CDialogSetTransientFor(NULL);
	if(response != CDIALOG_RESPONSE_YES)
	    return;

	/* Set style values to GTK default style values */
	StyleEditRestoreDefaultStyle(se);

#if 0
	/* Set style value to widgets */
	StyleEditSetStyleToWidgets(
	    se,
	    StyleEditCurrentState(se)
	);
#endif

	/* Notify about change */
	StyleEditAnyValueChangedCB(NULL, se);
}

/*
 *      Style Edit bg pixmap path browse callback.
 */
static void StyleEditBGPixmapPathCB(
	GtkWidget *widget, gpointer data
)
{
	gboolean status;
	gchar *startup_path;
	fb_type_struct **ftype = NULL, *ftype_rtn = NULL;
	gint total_ftypes = 0;
	gchar **path_rtn = NULL;
	gint total_path_rtns = 0;
	GtkWidget *toplevel;
	style_edit_struct *se = STYLE_EDIT(data);
	if((se == NULL) || FileBrowserIsQuery())
	    return;

	toplevel = gtk_widget_get_toplevel(se->toplevel);

	startup_path = g_dirname(
	    gtk_entry_get_text(GTK_ENTRY(se->bg_pixmap_name_entry))
	);

	/* Create file types list */
	FileBrowserTypeListNew(
	    &ftype, &total_ftypes,
	    ".xpm", "XPM Image"
	);
	FileBrowserTypeListNew(
	    &ftype, &total_ftypes,
	    "*.*", "All files"
	);

	/* Query user for background image */
	FileBrowserSetTransientFor(toplevel);
	status = FileBrowserGetResponse(
#if defined(PROG_LANGUAGE_SPANISH)
"La Imagen Selecta",
"Selecto",
"Cancele",
#elif defined(PROG_LANGUAGE_FRENCH)
"Image Privilégiée",
"Privilégié",
"Annuler",
#elif defined(PROG_LANGUAGE_GERMAN)
"Erlesenes Bildnis",
"Erlesen",
"Heben",
#elif defined(PROG_LANGUAGE_ITALIAN)
"Scegliere L'Immagine",
"Scegliere",
"Annullare",
#elif defined(PROG_LANGUAGE_DUTCH)
"Uitgezochte Beeld",
"Uitgezocht",
"Annuleer",
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Selecione Imagem",
"Selecione",
"Cancelamento",
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Utvalgt Avbilde",
"Utvalgt",
"Kanseller",
#else
"Select Image",
"Select",
"Cancel",
#endif
	    STRISEMPTY(startup_path) ? NULL : startup_path,
	    ftype, total_ftypes,
	    &path_rtn, &total_path_rtns,
	    &ftype_rtn
	);
	FileBrowserSetTransientFor(NULL);

	/* Got user response? */
	if(status)
	{
	    const gchar *path = (total_path_rtns > 0) ?
		path_rtn[0] : NULL;
	    if(!STRISEMPTY(path))
	    {
		GtkEntry *entry = GTK_ENTRY(se->bg_pixmap_name_entry);
		gtk_entry_set_text(entry, path);
		gtk_entry_set_position(entry, -1);

		StyleEditSetWidgetsToStyle(
		    se,
		    StyleEditCurrentState(se)
		);
		StyleEditPreviewDraw(se);
	    }
	}

	/* Delete file types list */
	FileBrowserDeleteTypeList(ftype, total_ftypes);

	g_free(startup_path);
}

/*
 *	Preview event signal callback.
 */
static gint StyleEditPreviewEventCB(
	gpointer widget, GdkEvent *event, gpointer data
)
{
	gint status = FALSE;
	GdkEventConfigure *configure;
	GdkEventExpose *expose;
	GdkEventKey *key;
	GdkEventButton *button;
	GdkEventFocus *focus;
	style_edit_struct *se = STYLE_EDIT(data);
	if((widget == NULL) || (event == NULL) || (se == NULL))
	    return(status);

	switch((gint)event->type)
	{
	  case GDK_CONFIGURE:
	    configure = (GdkEventConfigure *)event;
	    status = TRUE;
	    break;

	  case GDK_EXPOSE:
	    expose = (GdkEventExpose *)event;
	    StyleEditPreviewDraw(se);
	    status = TRUE;
	    break;

	  case GDK_VISIBILITY_NOTIFY:
	    status = TRUE;
	    break;

	  case GDK_KEY_PRESS:
	  case GDK_KEY_RELEASE:
	    key = (GdkEventKey *)event;
	    status = TRUE;
	    break;

	  case GDK_BUTTON_PRESS:
	    button = (GdkEventButton *)event;
	    if(!GTK_WIDGET_HAS_FOCUS(widget))
		gtk_widget_grab_focus(widget);
	    switch(button->button)
	    {
	      case 1:
		break;

	    }
	    status = TRUE;
	    break;

	  case GDK_BUTTON_RELEASE:
	    button = (GdkEventButton *)event;
	    status = TRUE;
	    break;

	  case GDK_FOCUS_CHANGE:
	    focus = (GdkEventFocus *)event;
	    if(focus->in && !GTK_WIDGET_HAS_FOCUS(widget))
	    {
		GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
		StyleEditPreviewDraw(se);
	    }
	    else if(!focus->in && GTK_WIDGET_HAS_FOCUS(widget))
	    {
		GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
		StyleEditPreviewDraw(se);
	    }
	    status = TRUE;
	    break;
	}

	return(status);
}


/*
 *	Updates the Style Edit's preview style and redraws it.
 */
static void StyleEditPreviewUpdate(style_edit_struct *se)
{
	GtkRcStyle *style;

	if(se == NULL)
	    return;

	style = gtk_rc_style_copy(se->style);
	gtk_widget_modify_style(
	    se->preview_da, style
	);
	GTK_RC_STYLE_UNREF(style)

	StyleEditPreviewDraw(se);
}

/*
 *	Redraws the Style Edit's preview.
 */
static void StyleEditPreviewDraw(style_edit_struct *se)
{
	gint width, height;
	GdkFont *font;
	GdkWindow *window;
	GdkDrawable *drawable;
	GdkGC *gc;
	GtkStateType state;
	GtkStyle *style;
	GtkWidget *w;

	if(se == NULL)
	    return;

	state = StyleEditCurrentState(se);
	w = se->preview_da;
	if(!GTK_WIDGET_VISIBLE(w) || !GTK_WIDGET_MAPPED(w))
	    return;

	width = w->allocation.width;
	height = w->allocation.height;
	style = gtk_widget_get_style(w);
	drawable = window = w->window;
	if((drawable == NULL) || (style == NULL) ||
	   (width <= 0) || (height <= 0)
	)
	    return;

	/* Draw background */
	gc = style->base_gc[state];
	gdk_draw_rectangle(
	    drawable, gc, TRUE,
	    0, 0, width, height
	);
	if(style->bg_pixmap[state] != NULL)
	    gtk_style_apply_default_background(
		style, drawable, FALSE, state,
		NULL,
		0, 0, width, height
	    );

	/* Draw foreground box & text */
	font = style->font;
	if(font != NULL)
	{
	    const gchar *s = "Sample Text";
	    const gint border = 2;
	    gint x, y, bw, bh, tw, th;
	    gint lbearing, rbearing, swidth, ascent, descent;

	    /* Calculate string geometry */
	    gdk_string_extents(
		font, s,
		&lbearing, &rbearing, &swidth, &ascent, &descent
	    );
	    tw = swidth;
	    th = font->ascent + font->descent;

	    /* Draw foreground box */
	    bw = MIN(width * 0.5f, tw + (6 * border));
	    bh = th + (6 * border);
	    x = (width * 0.25f) - (bw / 2);
	    y = (height / 2) - (bh / 2);
	    gtk_draw_box(
		style, drawable, state, GTK_SHADOW_OUT,
		x, y, bw, bh
	    );

	    /* Draw string */
	    x = (width * 0.25f) - (tw / 2);
	    y = (height / 2) - (th / 2);
	    gc = style->text_gc[state];
	    gdk_draw_string(
		drawable, font, gc,
		x + lbearing,
		y + font->ascent,
		s
	    );

	    /* Draw foreground rectangle around string */
	    bw = MIN(width * 0.5f, tw + (2 * border));
	    bh = th + (2 * border);
	    x = (width * 0.25f) - (bw / 2);
	    y = (height / 2) - (bh / 2);
	    gc = style->fg_gc[state];
	    gdk_draw_rectangle(
		drawable, gc, FALSE,
		x, y, bw, bh
	    );


	    /* Calculate string geometry */
	    s = "Base";
	    gdk_string_extents(
		font, s,
		&lbearing, &rbearing, &swidth, &ascent, &descent
	    );
	    tw = swidth;
	    th = font->ascent + font->descent;

	    /* Draw string on base */
	    x = (width * 0.75f) - (tw / 2);
	    y = (height / 2) - (th / 2);
	    gc = style->text_gc[state];
	    gdk_draw_string(
		drawable, font, gc,
		x + lbearing,
		y + font->ascent,
		s
	    );

	    /* Draw foreground rectangle on base */
	    bw = MIN(width * 0.5f, tw + (2 * border));
	    bh = th + (2 * border);
	    x = (width * 0.75f) - (bw / 2);
	    y = (height / 2) - (bh / 2);
	    gc = style->fg_gc[state];
	    gdk_draw_rectangle(
		drawable, gc, FALSE,
		x, y, bw, bh
	    );

	}

	/* Draw focus */
	if(GTK_WIDGET_HAS_FOCUS(w))
	    gtk_draw_focus(
		style, drawable,
		0, 0, width - 1, height - 1
	    );
}


/*
 *      Returns the current Style Edit's state.
 */
GtkStateType StyleEditCurrentState(style_edit_struct *se)
{
	GtkAdjustment *adj = se->state_adj;
	return((GtkStateType)CLIP(
	    adj->value, adj->lower, adj->upper - adj->page_size
	));
}


/*
 *      Creates a new Style Edit.
 */
style_edit_struct *StyleEditNew(
	GtkWidget *parent, const gchar *name
)
{
	const gint border_major = 5;
	gpointer entry_rtn, browse_rtn;
	GtkAdjustment *adj;
	GtkWidget *w, *parent2, *parent3, *parent4;
	style_edit_struct *se = STYLE_EDIT(
	    g_malloc0(sizeof(style_edit_struct))
	);

	se->freeze_count = 0;
	se->prev_state = GTK_STATE_NORMAL;
	se->state_adj = adj = (GtkAdjustment *)gtk_adjustment_new(
	    (gfloat)GTK_STATE_NORMAL,
	    0.0f, (gfloat)(STYLE_EDIT_STATES - 1),
	    1.0f, 1.0f, 0.0f
	);
	gtk_signal_connect(
	    GTK_OBJECT(adj), "value_changed",
	    GTK_SIGNAL_FUNC(StyleEditStateChangeCB), se
	);

	se->style = gtk_rc_style_new();


	/* Begin creating widgets */

	/* Toplevel */
	se->toplevel = w = gtk_vbox_new(FALSE, border_major);
	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);
	gtk_widget_show(w);
	parent = w;


	/* Hbox for label and state widgets */
	w = gtk_hbox_new(FALSE, border_major);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent2 = w;

	/* Name */
	if(!STRISEMPTY(name))
	{
	    w = gtk_label_new(name);
	    gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_LEFT);
	    gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	    gtk_widget_show(w);
	}

	/* Hbox for state widgets */
	w = gtk_hbox_new(FALSE, 0);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent3 = w;
	/* Previous Button */
	se->state_previous_btn = w = gtk_button_new();
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(StyleEditPreviousStateCB), se
	);
	gtk_widget_set_usize(w, 20, 20);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent4 = w;
	/* Arrow */
	w = gtk_arrow_new(GTK_ARROW_LEFT, GTK_SHADOW_OUT);
	gtk_container_add(GTK_CONTAINER(parent4), w);
	gtk_widget_show(w);

	/* Entry */
	se->state_entry = w = gtk_entry_new();
	gtk_widget_set_usize(w, 80, -1);
	gtk_entry_set_editable(GTK_ENTRY(w), FALSE);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);

	/* Next Button */
	se->state_next_btn = w = gtk_button_new();
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(StyleEditNextStateCB), se
	);
	gtk_widget_set_usize(w, 20, 20);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent4 = w;
	/* Arrow */
	w = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_OUT);
	gtk_container_add(GTK_CONTAINER(parent4), w);
	gtk_widget_show(w);


	/* Font Name */
	se->font_name_prompt = w = FSDPromptNewSimple(
	    "Font Name:", -1,
	    -1
	);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, TRUE, 0);
	gtk_widget_show(w);
	w = FSDPromptGetEntry(w);
	gtk_signal_connect(
	    GTK_OBJECT(w), "changed",
	    GTK_SIGNAL_FUNC(StyleEditAnyValueChangedCB), se
	);


	/* Hbox for multiple columns */
	w = gtk_hbox_new(FALSE, border_major);
	gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent2 = w;

	/* Vbox for Column 1 */
	w = gtk_vbox_new(FALSE, border_major);
	gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, TRUE, 0);
	gtk_widget_show(w);
	parent3 = w;

	/* Hbox for color buttons */
	w = gtk_hbox_new(TRUE, 0);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent4 = w;

	/* FG Button */
	se->fg_color_btn = w = CSDColorButtonNewSimple(
	    "FG:", -1
	);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	w = CSDColorButtonGetButton(w);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(StyleEditAnyValueChangedCB), se
	);

	/* BG Button */
	se->bg_color_btn = w = CSDColorButtonNewSimple(
	    "BG:", -1
	);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	w = CSDColorButtonGetButton(w);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(StyleEditAnyValueChangedCB), se
	);

	/* Text Button */
	se->text_color_btn = w = CSDColorButtonNewSimple(
	    "Text:", -1
	);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	w = CSDColorButtonGetButton(w);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(StyleEditAnyValueChangedCB), se
	);

	/* Base Button */
	se->base_color_btn = w = CSDColorButtonNewSimple(
	    "Base:", -1
	);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	w = CSDColorButtonGetButton(w);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(StyleEditAnyValueChangedCB), se
	);

	/* Reset button */
	w = GUIButtonPixmap(
	    (guint8 **)icon_clear_20x20_xpm
	);
	gtk_box_pack_start(GTK_BOX(parent4), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	gtk_signal_connect(
	    GTK_OBJECT(w), "clicked",
	    GTK_SIGNAL_FUNC(StyleEditResetCB), se
	);
	GUISetWidgetTip(w,
#if defined(PROG_LANGUAGE_SPANISH)
"El clic para reponer los valores"
#elif defined(PROG_LANGUAGE_FRENCH)
"Le déclic pour remettre à l'état initial des valeurs"
#elif defined(PROG_LANGUAGE_GERMAN)
"Klicken, werte nachzustellen"
#elif defined(PROG_LANGUAGE_ITALIAN)
"Lo scatto di ripristinare i valori"
#elif defined(PROG_LANGUAGE_DUTCH)
"Klik waarde te resetten"
#elif defined(PROG_LANGUAGE_PORTUGUESE)
"Clique a valores de reset"
#elif defined(PROG_LANGUAGE_NORWEGIAN)
"Klikk tilbakestille verdier"
#else
"Click to reset"
#endif
	);
	gtk_widget_show(w);



	/* Hbox for BG Pixmap Path */
	w = gtk_hbox_new(FALSE, border_major);
	gtk_box_pack_start(GTK_BOX(parent3), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent4 = w;

	w = GUIPromptBarWithBrowse(
	    NULL, "BG Pixmap Path:",
	    NULL, &entry_rtn, &browse_rtn,
	    se, StyleEditBGPixmapPathCB
	);
	gtk_box_pack_start(GTK_BOX(parent4), w, TRUE, TRUE, 0);
	gtk_widget_show(w);

	se->bg_pixmap_name_entry = w = (GtkWidget *)entry_rtn;
	gtk_signal_connect(
	    GTK_OBJECT(w), "changed",
	    GTK_SIGNAL_FUNC(StyleEditAnyValueChangedCB), se
	);


	/* Preview frame for column 2 */
#if 0
	w = gtk_frame_new(
"Preview"
	);
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_ETCHED_IN);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent3 = w;

	w = gtk_vbox_new(FALSE, 0);
	gtk_container_border_width(GTK_CONTAINER(w), border_major);
	gtk_container_add(GTK_CONTAINER(parent3), w);
	gtk_widget_show(w);
	parent4 = w;
#else
	w = gtk_vbox_new(FALSE, 0);
	gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
	gtk_widget_show(w);
	parent3 = w;
#endif

	w = gtk_frame_new(NULL);
	gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_IN);
	gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, TRUE, 0);
	gtk_widget_show(w);
	parent4 = w;

	/* Preview drawing area */
	se->preview_da = w = gtk_drawing_area_new();
	GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT | GTK_CAN_FOCUS);
	gtk_widget_add_events(
	    w,
	    GDK_STRUCTURE_MASK | GDK_EXPOSURE_MASK |
	    GDK_VISIBILITY_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK |
	    GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
	    GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
	    GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
	    GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "configure_event",
	    GTK_SIGNAL_FUNC(StyleEditPreviewEventCB), se
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "expose_event",
	    GTK_SIGNAL_FUNC(StyleEditPreviewEventCB), se
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "focus_in_event",
	    GTK_SIGNAL_FUNC(StyleEditPreviewEventCB), se
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "focus_out_event",
	    GTK_SIGNAL_FUNC(StyleEditPreviewEventCB), se
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "key_press_event",
	    GTK_SIGNAL_FUNC(StyleEditPreviewEventCB), se
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "key_release_event",
	    GTK_SIGNAL_FUNC(StyleEditPreviewEventCB), se
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "button_press_event",
	    GTK_SIGNAL_FUNC(StyleEditPreviewEventCB), se
	);
	gtk_signal_connect(
	    GTK_OBJECT(w), "button_release_event",
	    GTK_SIGNAL_FUNC(StyleEditPreviewEventCB), se
	);
	gtk_widget_set_usize(w, 220, -1);
	gtk_container_add(GTK_CONTAINER(parent4), w);
	gtk_widget_show(w);





	/* Update current state */
	gtk_signal_emit_by_name(
	    GTK_OBJECT(adj), "value_changed"
	);


	return(se);
}

/*
 *      Deletes the Style Edit.
 */
void StyleEditDelete(style_edit_struct *se)
{
	if(se == NULL)
	    return;

	gtk_widget_destroy(se->state_previous_btn);
	gtk_widget_destroy(se->state_entry);
	gtk_widget_destroy(se->state_next_btn);
	gtk_widget_destroy(se->font_name_prompt);
	gtk_widget_destroy(se->fg_color_btn);
	gtk_widget_destroy(se->bg_color_btn);
	gtk_widget_destroy(se->text_color_btn);
	gtk_widget_destroy(se->base_color_btn);
	gtk_widget_destroy(se->bg_pixmap_name_entry);
	gtk_widget_destroy(se->preview_da);

	gtk_widget_destroy(se->toplevel);
	gtk_object_unref(GTK_OBJECT(se->state_adj));

	GTK_RC_STYLE_UNREF(se->style)

	g_free(se);
}

/*
 *      Sets values on the Style Edit's widgets to its style
 *      structure.
 */
static void StyleEditSetWidgetsToStyle(
	style_edit_struct *se, GtkStateType state
)
{
	csd_color_struct csd_c;
	GtkRcStyle *style;

	if((se == NULL) || (state < 0) || (state >= STYLE_EDIT_STATES))
	    return;

	style = se->style;

	/* Font Name */
	g_free(style->font_name);
	style->font_name = STRDUP(
	    FSDPromptGetFontName(se->font_name_prompt)
	);

	style->color_flags[state] |= GTK_RC_FG | GTK_RC_BG |
				     GTK_RC_TEXT | GTK_RC_BASE;

	/* FG Color */
	CSDColorButtonGetColor(se->fg_color_btn, &csd_c);
	StyleEditCSDColorToGdkColor(&csd_c, &style->fg[state]);

	/* BG Color */
	CSDColorButtonGetColor(se->bg_color_btn, &csd_c);
	StyleEditCSDColorToGdkColor(&csd_c, &style->bg[state]);

	/* Text Color */
	CSDColorButtonGetColor(se->text_color_btn, &csd_c);
	StyleEditCSDColorToGdkColor(&csd_c, &style->text[state]);

	/* Base Color */
	CSDColorButtonGetColor(se->base_color_btn, &csd_c);
	StyleEditCSDColorToGdkColor(&csd_c, &style->base[state]);

	/* BG Pixmap Name */
	g_free(style->bg_pixmap_name[state]);
	style->bg_pixmap_name[state] = STRDUP(
	    gtk_entry_get_text(GTK_ENTRY(se->bg_pixmap_name_entry))
	);
}

/*
 *      Gets values from the Style Edit's style structure and sets
 *      it to the widgets.
 */
static void StyleEditSetStyleToWidgets(
	style_edit_struct *se, GtkStateType state
)
{
	const gchar *s;
	GtkRcFlags color_flags;
	csd_color_struct csd_c;
	GtkRcStyle *style;

	if((se == NULL) || (state < 0) || (state >= STYLE_EDIT_STATES))
	    return;

	style = se->style;
	color_flags = style->color_flags[state];

	se->freeze_count++;

	/* Font Name */
	FSDPromptSetFontName(
	    se->font_name_prompt, style->font_name
	);

	/* FG Color */
	if(color_flags & GTK_RC_FG)
	{
	    StyleEditGdkColorToCSDColor(
		&style->fg[state], &csd_c
	    );
	    CSDColorButtonSetColor(se->fg_color_btn, &csd_c);
	}

	/* BG Color */
	if(color_flags & GTK_RC_BG)
	{
	    StyleEditGdkColorToCSDColor(
		&style->bg[state], &csd_c
	    );
	    CSDColorButtonSetColor(se->bg_color_btn, &csd_c);
	}

	/* Text Color */
	if(color_flags & GTK_RC_TEXT)
	{
	    StyleEditGdkColorToCSDColor(
		&style->text[state], &csd_c
	    );
	    CSDColorButtonSetColor(se->text_color_btn, &csd_c);
	}

	/* Base Color */
	if(color_flags & GTK_RC_BASE)
	{
	    StyleEditGdkColorToCSDColor(
		&style->base[state], &csd_c
	    );
	    CSDColorButtonSetColor(se->base_color_btn, &csd_c);
	}

	/* BG Pixmap Name */
	s = style->bg_pixmap_name[state];
	gtk_entry_set_text(
	    GTK_ENTRY(se->bg_pixmap_name_entry),
	    (s != NULL) ? s : ""
	);

	se->freeze_count--;


	/* Update preview style */
	StyleEditPreviewUpdate(se);
}

/*
 *	Sets the Style Edit's style values.
 */
void StyleEditSetStyle(style_edit_struct *se, const GtkRcStyle *style)
{
	gint i;
	GtkStateType state;
	GtkRcStyle *tar_style;

	if((se == NULL) || (style == NULL))
	    return;

	tar_style = se->style;

	g_free(tar_style->name);
	tar_style->name = STRDUP(style->name);

	g_free(tar_style->font_name);
	tar_style->font_name = STRDUP(style->font_name);

	g_free(tar_style->fontset_name);
	tar_style->fontset_name = STRDUP(style->fontset_name);

	for(i = 0; i < STYLE_EDIT_STATES; i++)
	{
	    g_free(tar_style->bg_pixmap_name[i]);
	    tar_style->bg_pixmap_name[i] = STRDUP(style->bg_pixmap_name[i]);

	    tar_style->color_flags[i] = style->color_flags[i];

	    memcpy(&tar_style->fg[i], &style->fg[i], sizeof(GdkColor));
	    memcpy(&tar_style->bg[i], &style->bg[i], sizeof(GdkColor));
	    memcpy(&tar_style->text[i], &style->text[i], sizeof(GdkColor));
	    memcpy(&tar_style->base[i], &style->base[i], sizeof(GdkColor));
	}

	tar_style->engine = style->engine;
	tar_style->engine_data = style->engine_data;

	/* Set values from the newly updated style structure to the
	 * widgets
	 */
	state = StyleEditCurrentState(se);
	StyleEditSetStyleToWidgets(se, state);

	StyleEditPreviewDraw(se);
}

/*
 *	Gets the Style Edit's style.
 */
GtkRcStyle *StyleEditGetStyle(style_edit_struct *se)
{
	/* Make sure values in the widgets have been set to the style
	 * structure
	 */
	StyleEditSetWidgetsToStyle(
	    se, StyleEditCurrentState(se)
	);
	return(se->style);
}

/*
 *	Sets the Style Edit's style from the given GtkStyle.
 */
static void StyleEditSetStyleFromStyle(
	style_edit_struct *se, const GtkStyle *style
)
{
	gint i;
	const GtkStyle *src_style = style;
	GtkRcStyle *tar_style;

	if(se == NULL)
	    return;

	tar_style = se->style;

	g_free(tar_style->font_name);
	tar_style->font_name = NULL;

	for(i = 0; i < STYLE_EDIT_STATES; i++)
	{
	    tar_style->color_flags[i] |= GTK_RC_FG | GTK_RC_BG |
		GTK_RC_TEXT | GTK_RC_BASE;
	    memcpy(&tar_style->fg[i], &src_style->fg[i], sizeof(GdkColor));
	    memcpy(&tar_style->bg[i], &src_style->bg[i], sizeof(GdkColor));
	    memcpy(&tar_style->text[i], &src_style->text[i], sizeof(GdkColor));
	    memcpy(&tar_style->base[i], &src_style->base[i], sizeof(GdkColor));

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

/*
 *	Sets the Style Edit's style to the values of the GTK default
 *	style.
 */
void StyleEditRestoreDefaultStyle(style_edit_struct *se)
{
	if(se == NULL)
	    return;

	StyleEditSetStyleFromStyle(
	    se,
	    gtk_widget_get_default_style()
	);
	StyleEditSetStyleToWidgets(
	    se,
	    StyleEditCurrentState(se)
	);
}


/*
 *      Sets the Style Edit's changed callback.
 */
void StyleEditSetChangedCB(
	style_edit_struct *se,
	void (*changed_cb)(
		style_edit_struct *,
		gpointer
	),
	gpointer changed_client_data
)
{
	if(se == NULL)
	    return;

	se->changed_cb = changed_cb;
	se->changed_client_data = changed_client_data;
}

