/*
	od_emil_button.c

	1999-04-22:
		ODEmilButton is ready for release.
		Some inconsistencies might remain.

	1999-05-02:
		Emil submitted suggestions and a bug report.
		I could not find the bug. I believe he just forgot to set his vbox to assign
		equal heights to its children.
		Fixes:	The default style was not restored after a secondary click if there
				was only a secondary choice.

	1999-05-03:
		Emil still wanted to know the index.
		The signal is modified to pass an ODEmilButtonChoice as a second parameter.
		The index is found within the choice structure, as is index and choice user_data.
		Please don't mutate the choice! Use "const" in the function prototype.
	
	1999-05-05:
		Change: Changed the signal to the way Emil wanted (originally ...)
		Added:	"Config mode" with menu off and recessed highlighting.
				Colors and text can not be set seperately.
		Fixes:	Default style is restored when the primary label is removed/changed.
				Now queues drawing operations more often (when needed)

	1999-05-06:
		Change:	Removed color handling and put in a seperate module. Maybe Emil wants to use it.
		Fixes:	Default button color is correct again. (didn't test with it.. stupid me)
				Button releases were grabbed first after signal had been emitted.
				I hacked gentoo to test with all of this, so it should work.

	This module is written and maintained by Johan Hanson <johan@tiq.com>
*/

#include <gdk/gdk.h>

#include <gtk/gtksignal.h>
#include <gtk/gtkbin.h>
#include <gtk/gtklabel.h>
#include <gtk/gtkmenu.h>
#include <gtk/gtkmenuitem.h>

#include "odemilbutton.h"
#include "../colorutil.h"

#define DEBUG 0

/*** Private Types ******************************************************************************************/

enum {
	ACTIVATE,
	LAST_SIGNAL
};

typedef struct _ODHSL {
	double h, s, l;
} ODHSL;

typedef struct {
	GtkStyle *newstyle;
	GtkStyle *oldstyle;
} ODStylePackage;


/*** Function prototypes ************************************************************************************/

static void od_emil_button_class_init		(ODEmilButtonClass *klass);
static void od_emil_button_init				(ODEmilButton *mbutton);
static void od_emil_button_destroy			(GtkObject *object);

static void od_emil_button_size_request		(GtkWidget *widget, GtkRequisition *requisition);
static void od_emil_button_size_allocate	(GtkWidget *widget, GtkAllocation *allocation);

/* events */
static void od_emil_button_paint			(GtkWidget *widget, GdkRectangle *area);
static void od_emil_button_draw				(GtkWidget *widget, GdkRectangle *area);
static gint od_emil_button_expose			(GtkWidget *widget, GdkEventExpose *event);

static gint od_emil_button_button_press		(GtkWidget *widget, GdkEventButton *event);
static gint od_emil_button_button_release	(GtkWidget *widget, GdkEventButton *event);

static void od_emil_button_enter			(GtkButton *button);
static void od_emil_button_leave			(GtkButton *button);

/* methods */
static GtkType od_emil_button_child_type	(GtkContainer *container);
static void    od_emil_button_paint_dogear	(GtkWidget *widget, GdkRectangle *area);
static void    od_emil_button_paint_menutab	(GtkWidget *widget, GdkRectangle *area);

/* internal */
static void od_emil_button_size_calc		(ODEmilButton *button);

/*
static void od_emil_button_blend			(GdkColor *dest, const GdkColor *src,
											 const GdkColor *orig_dest, const GdkColor *orig_src);

static GtkStyle * od_emil_button_make_style	(GtkStyle *style, const GdkColor *fg, const GdkColor *bg);
static void od_emil_button_set_style_recurse (GtkWidget *widget, ODStylePackage *op);

static void od_emil_button_restore_style_recurse (GtkWidget *widget, gpointer dummy);
*/

/* fiddling with menu and menu items */
static void od_emil_button_detacher			(GtkWidget *widget, GtkMenu *menu);
static void od_emil_button_position			(GtkMenu *menu, gint *x, gint *y, gpointer userdata);
static void od_emil_button_deactivate		(GtkMenuShell *menu_shell, ODEmilButton *button);
static void od_emil_button_select			(GtkMenuItem *menu_item, ODEmilButtonChoice *choice);
static void od_emil_button_popup			(ODEmilButton *button, GdkEvent *event);
static void od_emil_button_set				(ODEmilButton *button, guint index);


/*** Global Variables **************************************************************************************/
static GtkBinClass *parent_class = NULL;
static guint emil_button_signals[LAST_SIGNAL] = { 0 };


/*** Type Functions ****************************************************************************************/
GtkType od_emil_button_get_type (void) {
	static GtkType type = 0;
	
	if (!type) {
		static const GtkTypeInfo info = {
			"ODEmilButton",
			sizeof (ODEmilButton),
			sizeof (ODEmilButtonClass),
			(GtkClassInitFunc) od_emil_button_class_init,
			(GtkObjectInitFunc) od_emil_button_init,
			/* reserved_1 */ NULL,
			/* reserved_2 */ NULL,
			(GtkClassInitFunc) NULL,
		};

		type = gtk_type_unique (gtk_button_get_type(), &info);
	}

	return type;
}

static void od_emil_button_class_init (ODEmilButtonClass *klass) {
	GtkObjectClass *object_class;
	GtkWidgetClass *widget_class;
	GtkContainerClass *container_class;
	GtkButtonClass *button_class;
	
	object_class = (GtkObjectClass *) klass;
	widget_class = (GtkWidgetClass *) klass;
	container_class = (GtkContainerClass *) klass;
	button_class = (GtkButtonClass *) klass;
	parent_class = gtk_type_class (GTK_TYPE_BUTTON);

	emil_button_signals[ACTIVATE] =
		gtk_signal_new ("activate",
						GTK_RUN_FIRST,
						object_class->type,
						GTK_SIGNAL_OFFSET (ODEmilButtonClass, activate),
						gtk_marshal_NONE__POINTER_UINT,
						GTK_TYPE_NONE, 2, GTK_TYPE_POINTER, GTK_TYPE_UINT);

	gtk_object_class_add_signals (object_class, emil_button_signals, LAST_SIGNAL);

	object_class->destroy		= od_emil_button_destroy;
	
	widget_class->draw			= od_emil_button_draw;
	widget_class->size_request	= od_emil_button_size_request;
	widget_class->size_allocate	= od_emil_button_size_allocate;
	widget_class->expose_event	= od_emil_button_expose;
	widget_class->button_press_event	= od_emil_button_button_press;
	widget_class->button_release_event	= od_emil_button_button_release;
/*
	widget_class->key_press_event		= od_emil_button_key_press;
	widget_class->key_release_event		= od_emil_button_key_release;
*/

	container_class->child_type	= od_emil_button_child_type;

	button_class->enter			= od_emil_button_enter;
	button_class->leave			= od_emil_button_leave;

	klass->activate				= NULL;
	klass->paint_dogear			= od_emil_button_paint_dogear;
	klass->paint_menutab		= od_emil_button_paint_menutab;
}

static void od_emil_button_init (ODEmilButton *button) {
	guint8 i;
	GTK_WIDGET_SET_FLAGS (button, GTK_CAN_FOCUS);
	GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_DEFAULT | GTK_RECEIVES_DEFAULT );
	
	button->menu = NULL;
	for (i=0; i<OD_EMIL_BUTTON_MAX_CHOICES; i++) {
		button->choices[i].widget = NULL;
		button->choices[i].user_data = NULL;
	}
	button->oldstyle = NULL;
	button->width = 0;
	button->height = 0;
	button->button = 0;
	button->nth = 1;
	button->config = 0;

	gtk_widget_ensure_style(GTK_WIDGET(button));
	button->oldstyle = gtk_widget_get_style(GTK_WIDGET(button));
}

static GtkType od_emil_button_child_type (GtkContainer *container) {
	if (!GTK_BIN(container)->child)
		return GTK_TYPE_WIDGET;
	else
		return GTK_TYPE_NONE;
}


/* New */
GtkWidget * od_emil_button_new() {
	return GTK_WIDGET ( gtk_type_new (od_emil_button_get_type ()));
}


static void od_emil_button_destroy (GtkObject *object) {
	ODEmilButton *button;
	guint16 i, n;

	g_return_if_fail (object != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(object));
	
	button = OD_EMIL_BUTTON(object);

	od_emil_button_remove_widget(button, OD_EMIL_BUTTON_SECONDARY);
	od_emil_button_remove_widget(button, OD_EMIL_BUTTON_PRIMARY);
	od_emil_button_remove_menu(button);
	
	if (GTK_OBJECT_CLASS (parent_class)->destroy)
		(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}


/* get, set and remove */
GtkWidget * od_emil_button_get_widget (const ODEmilButton *button, guint index) {
	g_return_if_fail (button != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(button));
	g_return_if_fail (index < OD_EMIL_BUTTON_MAX_CHOICES);

	return button->choices[index].widget;
}


void od_emil_button_set_label (ODEmilButton *button, guint index,
							   const gchar *label_text, const GdkColor *fg, const GdkColor *bg,
							   const gpointer user_data)
{
	g_return_if_fail (button != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(button));
	g_return_if_fail (index < OD_EMIL_BUTTON_MAX_CHOICES);

	od_emil_button_set_text(button, index, label_text);
	od_emil_button_set_colors(button, index, fg, bg);
	button->choices[index].user_data = user_data;

/*	
	GtkWidget *label_widget;
	GtkStyle *newstyle;
	
	g_return_if_fail (button != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(button));

	label_widget = gtk_label_new(label_text);
	gtk_misc_set_alignment (GTK_MISC (label_widget), 0.5, 0.5);

	if (bg || fg) {
		newstyle = od_emil_button_make_style(label_widget, fg, bg);
		if (index == OD_EMIL_BUTTON_SECONDARY) {
			newstyle->bg[GTK_STATE_ACTIVE] = newstyle->bg[GTK_STATE_NORMAL];
			newstyle->fg[GTK_STATE_ACTIVE] = newstyle->fg[GTK_STATE_NORMAL];
		}
		gtk_widget_set_style(label_widget, newstyle);
	} else {
		gtk_widget_ensure_style(GTK_WIDGET(label_widget));
	}

	od_emil_button_set_widget(button, index, label_widget, user_data);
*/
}


void od_emil_button_set_widget (ODEmilButton *button, guint index,
								GtkWidget *widget, const gpointer user_data)
{
	ODEmilButtonChoice * choice;
	
	g_return_if_fail (button != NULL);
	g_return_if_fail (widget != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(button));
	g_return_if_fail (index < OD_EMIL_BUTTON_MAX_CHOICES);

	if (button->choices[index].widget && button->choices[index].widget!=widget) {
		od_emil_button_remove_widget(button, index);
	}

	button->choices[index].widget = widget;
	button->choices[index].user_data = user_data;

	if (widget) {
		gtk_widget_ensure_style(widget);
		if (button->oldstyle == NULL) {
			gtk_widget_ensure_style(GTK_WIDGET(button));
			button->oldstyle = gtk_widget_get_style(GTK_WIDGET(button));
		}
	
		gtk_widget_ref(widget);
		if (index == OD_EMIL_BUTTON_PRIMARY) {
			gtk_widget_set_style(GTK_WIDGET(button), gtk_widget_get_style(widget));
			od_emil_button_set(button, OD_EMIL_BUTTON_PRIMARY);
		}
		gtk_widget_show(widget);
	}
	od_emil_button_size_calc(button);
	if (GTK_WIDGET_DRAWABLE(button))
		gtk_widget_queue_draw (GTK_WIDGET(button));
	if (GTK_WIDGET (button)->parent)
		gtk_widget_queue_resize (GTK_WIDGET(button));
}


void od_emil_button_remove_widget (ODEmilButton *button, guint index) {
	ODEmilButtonChoice *choice;

	g_return_if_fail (button != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(button));
	g_return_if_fail (index < OD_EMIL_BUTTON_MAX_CHOICES);

  #if DEBUG
	puts("od_emil_button_remove_widget()");
  #endif
	choice = &(button->choices[index]);
	if (choice->widget) {
		if (index == OD_EMIL_BUTTON_PRIMARY && button->oldstyle) {
			gtk_widget_set_style(GTK_WIDGET(button), button->oldstyle);
		}
	
		if (GTK_BIN(button)->child == choice->widget) {
			gtk_container_remove(GTK_CONTAINER(button), choice->widget);
		} else {
			gtk_widget_unref(choice->widget);
		}
		button->button = 0;
		choice->widget = NULL;
		choice->user_data = NULL;
/*
		od_emil_button_set(button, OD_EMIL_BUTTON_PRIMARY);
*/		
	}
	od_emil_button_size_calc(button);
	if (GTK_WIDGET_DRAWABLE (button))
		gtk_widget_queue_draw (GTK_WIDGET (button));
}


GtkMenu * od_emil_button_get_menu (const ODEmilButton *button) {
	g_return_if_fail (button != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(button));

	return GTK_MENU(button->menu);
}


void od_emil_button_set_menu (ODEmilButton *button, GtkMenu *menu) {
	g_return_if_fail (button != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(button));
	g_return_if_fail (menu != NULL);
	g_return_if_fail (GTK_IS_MENU(menu));

	if (button->menu)
		od_emil_button_remove_menu(button);

  #if DEBUG
	puts("od_emil_button_set_menu() - entered");
  #endif

	button->menu = GTK_WIDGET(menu);
	gtk_menu_attach_to_widget (menu, GTK_WIDGET(button), od_emil_button_detacher);
	gtk_signal_connect (GTK_OBJECT(menu), "deactivate", (GtkSignalFunc) od_emil_button_deactivate, button);
	if (GTK_WIDGET_DRAWABLE (button))
		gtk_widget_queue_draw (GTK_WIDGET (button));
}


void od_emil_button_remove_menu (ODEmilButton *button) {
	g_return_if_fail (button != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(button));

	if (button->menu) {
		gtk_menu_detach(GTK_MENU(button->menu));
		button->menu = NULL;
	}
	if (GTK_WIDGET_DRAWABLE (button))
		gtk_widget_queue_draw (GTK_WIDGET (button));
}


void od_emil_button_set_active (ODEmilButton *button, guint nth) {
	GtkWidget *menu_item;
	GList *list;
	
	g_return_if_fail (button != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(button));

	button->nth = nth+1;
}


void od_emil_button_set_none_active (ODEmilButton *button) {
	g_return_if_fail (button != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(button));

	if (button->nth && button->menu)
		col_restore_style (GTK_WIDGET(button->menu));

	button->nth = 0;
}


/* Size, requisitions and allocations */
static void od_emil_button_size_calc (ODEmilButton *button) {
	GtkWidget *child;
	GtkRequisition requisition;
	guint16 i, width=0, height=0;
	
	g_return_if_fail(button != NULL);
	g_return_if_fail(OD_IS_EMIL_BUTTON(button));

	for (i=0; i<OD_EMIL_BUTTON_MAX_CHOICES; i++) {
		child = button->choices[i].widget;
		
		if (child) {
			if (GTK_WIDGET_VISIBLE(child)) {
				gtk_widget_size_request(child, &requisition);
				width  = MAX(width,  requisition.width);
				height = MAX(height, requisition.height);
			}
		}
	}

	button->width = width;
	button->height = height;

  #if DEBUG
	printf("size calculated: %d x %d\n", width, height);
  #endif
}


static void od_emil_button_size_request (GtkWidget *widget, GtkRequisition *requisition) {
	ODEmilButton *button;

	g_return_if_fail (widget != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(widget));
	g_return_if_fail (requisition != NULL);

	button = OD_EMIL_BUTTON(widget);
	
	requisition->width  = 2 * (GTK_CONTAINER(widget)->border_width + 1 +
							   GTK_WIDGET(widget)->style->klass->xthickness);
	requisition->height = 2 * (GTK_CONTAINER(widget)->border_width + 1 +
							   GTK_WIDGET(widget)->style->klass->ythickness);
	
	od_emil_button_size_calc(button);
	
	requisition->width += button->width;
	requisition->height += button->height;
/*	
	if (button->menu)
		requisition->width += 6;
*/

  #if DEBUG
	printf("size_request: %d x %d\n", requisition->width, requisition->height);
  #endif
}


static void od_emil_button_size_allocate (GtkWidget *widget, GtkAllocation *allocation) {
	GtkWidget *child;
	ODEmilButton *button;
	GtkAllocation child_allocation;
	guint border_width, n;

	g_return_if_fail (widget != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(widget));
	g_return_if_fail (allocation != NULL);

	button = OD_EMIL_BUTTON(widget);
	widget->allocation = *allocation;
	border_width = GTK_CONTAINER(widget)->border_width;

	if (GTK_WIDGET_REALIZED(widget))
		gdk_window_move_resize(widget->window,
							   widget->allocation.x + border_width,
							   widget->allocation.y + border_width,
							   widget->allocation.width - 2*border_width,
							   widget->allocation.height - 2*border_width);
	
	if (child = GTK_BIN(widget)->child) {
		if (GTK_WIDGET_VISIBLE(child)) {
			child_allocation.x = GTK_WIDGET (widget)->style->klass->xthickness + 1 /* + border_width */ ;
			child_allocation.y = GTK_WIDGET (widget)->style->klass->ythickness + 1 /* + border_width */ ;
			child_allocation.width  = MAX(1, (gint)widget->allocation.width - 2 * (child_allocation.x + border_width));
			child_allocation.height = MAX(1, (gint)widget->allocation.height - 2 * (child_allocation.y + border_width));

		  /*
			n = child_allocation.width - child->requisition.width;
			if (button->menu && n <= 12 && child == button->choices[OD_EMIL_BUTTON_PRIMARY].widget) {
				child_allocation.width -= n/2;
			}
		  */
			
			gtk_widget_size_allocate (child, &child_allocation);
		}
	}
  #if DEBUG
	printf("size_allocate: %d,%d: %d x %d\n", widget->allocation.x,     widget->allocation.y,
											  widget->allocation.width, widget->allocation.height);
	printf("        child: %d,%d: %d x %d\n", child_allocation.x,     child_allocation.y,
											  child_allocation.width, child_allocation.height);
  #endif
}


/* Rendering
*/
static void od_emil_button_paint_dogear (GtkWidget *widget, GdkRectangle *area) {
	GdkPoint pnts[5];
	GtkStateType state_type;
	GtkStyle *style;
	gint x, y, width, height, i;
	
	g_return_if_fail (widget != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(widget));

	state_type = GTK_WIDGET_STATE(widget);
	style = gtk_widget_get_style(widget);

	if (GTK_WIDGET_DRAWABLE(widget) && state_type != GTK_STATE_ACTIVE) {
		x = GTK_CONTAINER (widget)->border_width;
		y = x;
		width = widget->allocation.width - 2 * x;
		height = widget->allocation.height - 2 * y ;

		if (GTK_WIDGET_HAS_FOCUS (widget)) {
			x += 1;		y += 1;
			width -= 2;	height -= 2;
		}
		if (OD_EMIL_BUTTON(widget)->config == 3) {
			width -= 1;	y += 1;
		}

		pnts[0].x = x+width-6;
		pnts[0].y = y;
		pnts[1].x = x+width-6;
		pnts[1].y = y+5;
		pnts[2].x = x+width-1;
		pnts[2].y = y+5;
		pnts[3].x = x+width-1;
		pnts[3].y = y+4;
		pnts[4].x = x+width-5;
		pnts[4].y = y;

/*		gdk_window_clear_area (widget->window, x+width-6, y, 6, 6);
*/		
		gdk_gc_set_clip_rectangle (style->bg_gc[GTK_STATE_INSENSITIVE], area);
		gdk_draw_rectangle(widget->window, style->bg_gc[GTK_STATE_INSENSITIVE], TRUE, x+width-4, y, 4, 4);
		gdk_gc_set_clip_rectangle (style->bg_gc[GTK_STATE_INSENSITIVE], NULL);
		
		if (state_type == GTK_STATE_INSENSITIVE) {
			gdk_gc_set_clip_rectangle (style->bg_gc[GTK_STATE_INSENSITIVE], area);
			gdk_gc_set_clip_rectangle (style->light_gc[GTK_STATE_INSENSITIVE], area);
			gdk_gc_set_clip_rectangle (style->dark_gc[GTK_STATE_INSENSITIVE], area);

			for (i=0; i<5; i++)
				pnts[i].y++;
			
			gdk_draw_polygon (widget->window, style->bg_gc[GTK_STATE_INSENSITIVE], TRUE, pnts, 5);
			gdk_draw_polygon (widget->window, style->light_gc[GTK_STATE_INSENSITIVE], FALSE, pnts, 5);

			for (i=0; i<5; i++) {
				pnts[i].x--;
				pnts[i].y--;
			}

			gdk_draw_polygon (widget->window, style->dark_gc[GTK_STATE_INSENSITIVE], FALSE, pnts, 5);
			
			gdk_gc_set_clip_rectangle (style->bg_gc[GTK_STATE_INSENSITIVE], NULL);
			gdk_gc_set_clip_rectangle (style->light_gc[GTK_STATE_INSENSITIVE], NULL);
			gdk_gc_set_clip_rectangle (style->dark_gc[GTK_STATE_INSENSITIVE], NULL);
		} else
		{
			gdk_gc_set_clip_rectangle (style->white_gc, area);
			gdk_gc_set_clip_rectangle (style->black_gc, area);

			gdk_draw_polygon (widget->window, style->white_gc, TRUE, pnts, 5);
			gdk_draw_polygon (widget->window, style->black_gc, FALSE, pnts, 5);
			
			gdk_gc_set_clip_rectangle (style->black_gc, NULL);
			gdk_gc_set_clip_rectangle (style->white_gc, NULL);
		}
	}
}


static void od_emil_button_paint_menutab (GtkWidget *widget, GdkRectangle *area) {
	GdkPoint pnts[3];
	GtkStateType state_type;
	GtkStyle *style;
	gint x, y, width, height, i;
	
	g_return_if_fail (widget != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(widget));

	state_type = GTK_WIDGET_STATE(widget);
	style = gtk_widget_get_style(widget);

	if (GTK_WIDGET_DRAWABLE(widget) && state_type != GTK_STATE_ACTIVE) {
		x = GTK_CONTAINER (widget)->border_width;
		y = x;
		width = widget->allocation.width - 2 * x;
		height = widget->allocation.height - 2 * y ;

		if (GTK_WIDGET_HAS_FOCUS (widget)) {
			x += 1;		y += 1;
			width -= 2;	height -= 2;
		}

		if (OD_EMIL_BUTTON(widget)->choices[OD_EMIL_BUTTON_SECONDARY].widget) {
			width -= 4;
			if (OD_EMIL_BUTTON(widget)->config == 3) {
				width -=1;
			}
		}
/*
		gdk_gc_set_clip_rectangle (style->light_gc[state_type], area);
		gdk_gc_set_clip_rectangle (style->dark_gc[state_type], area);

		gdk_draw_line(widget->window, style->dark_gc[state_type],
					  x+width-5, y+height/2+3, x+width-3, y+height/2-2);

		gdk_draw_line(widget->window, style->light_gc[state_type],
					  x+width-6, y+height/2+3, x+width-8, y+height/2-2);

		gdk_draw_line(widget->window, style->light_gc[state_type],
					  x+width-8, y+height/2-2, x+width-3, y+height/2-2);
*/
/*
		pnts[0].x = x+width-8;
		pnts[0].y = y+height/2 - 2;
		pnts[1].x = x+width-6;
		pnts[1].y = y+height/2 + 1;
		pnts[2].x = x+width-3;
		pnts[2].y = y+height/2 - 2;
*/
		pnts[0].x = x+width-8;
		pnts[0].y = y+3;
		pnts[1].x = x+width-6;
		pnts[1].y = y+6;
		pnts[2].x = x+width-3;
		pnts[2].y = y+3;


		if (state_type == GTK_STATE_INSENSITIVE) {
			gdk_gc_set_clip_rectangle (style->dark_gc[GTK_STATE_INSENSITIVE], area);
			gdk_gc_set_clip_rectangle (style->light_gc[GTK_STATE_INSENSITIVE], area);

			for (i=0; i<3; i++)
				pnts[i].x--;
			
			gdk_draw_polygon (widget->window, style->light_gc[GTK_STATE_INSENSITIVE], FALSE, pnts, 3);

			pnts[0].x--;
			pnts[0].y--;
			pnts[1].x--;
			pnts[2].y--;
			
			gdk_draw_polygon (widget->window, style->dark_gc[GTK_STATE_INSENSITIVE], FALSE, pnts, 3);

			gdk_gc_set_clip_rectangle (style->dark_gc[GTK_STATE_INSENSITIVE], NULL);
			gdk_gc_set_clip_rectangle (style->light_gc[GTK_STATE_INSENSITIVE], NULL);
		} else {
			gdk_gc_set_clip_rectangle (style->black_gc, area);
			gdk_draw_polygon (widget->window, style->black_gc, TRUE, pnts, 3);
			gdk_gc_set_clip_rectangle (style->black_gc, NULL);
		}
	}
}


static void od_emil_button_paint (GtkWidget *widget, GdkRectangle *area) {
	ODEmilButton *button;
	GtkStateType state_type;
	gint x, y, width, height;

	g_return_if_fail (widget != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(widget));

	if (GTK_WIDGET_DRAWABLE (widget)) {
		button = OD_EMIL_BUTTON (widget);

		state_type = GTK_WIDGET_STATE (widget);
		
		x = GTK_CONTAINER (widget)->border_width;
		y = x;
		width = widget->allocation.width - 2 * x;
		height = widget->allocation.height - 2 * y ;

		gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
		gdk_window_clear_area (widget->window, area->x, area->y, area->width, area->height);

		if (GTK_WIDGET_HAS_FOCUS (widget)) {
			x += 1;
			y += 1;
			width -= 2;
			height -= 2;
		}

		gtk_paint_box (widget->style, widget->window, state_type,
					   (state_type==GTK_STATE_ACTIVE || button->config==3) ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
					   area, widget, "multibutton", x, y, width, height);

		/* paint dog ear */
		if (button->choices[OD_EMIL_BUTTON_SECONDARY].widget
			&& (((ODEmilButtonClass *)(GTK_OBJECT(widget)->klass))->paint_dogear))
			((ODEmilButtonClass *)(GTK_OBJECT(widget)->klass))->paint_dogear(widget, area);
		
		if (button->menu
			&& button->nth
			&& ((ODEmilButtonClass *)(GTK_OBJECT(widget)->klass))->paint_menutab)
			((ODEmilButtonClass *)(GTK_OBJECT(widget)->klass))->paint_menutab(widget, area);

		if (GTK_WIDGET_HAS_FOCUS (widget)) {
			gtk_paint_focus (widget->style, widget->window, area, widget, "multibutton",
							 x-1, y-1, width + 1, height + 1);
		}
	}
}


/* copied directly from GtkButton */
static void od_emil_button_draw (GtkWidget *widget, GdkRectangle *area) {
	ODEmilButton *button;
	GdkRectangle child_area;
	GdkRectangle tmp_area;
	
	g_return_if_fail (widget != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON (widget));
	g_return_if_fail (area != NULL);
	
	if (GTK_WIDGET_DRAWABLE (widget)) {
		button = OD_EMIL_BUTTON (widget);
		
		tmp_area = *area;
		tmp_area.x -= GTK_CONTAINER (button)->border_width;
		tmp_area.y -= GTK_CONTAINER (button)->border_width;
		
		od_emil_button_paint (widget, &tmp_area);
		
		if (   GTK_BIN (button)->child
			&& gtk_widget_intersect (GTK_BIN (button)->child, &tmp_area, &child_area))
		{
			gtk_widget_draw (GTK_BIN (button)->child, &child_area);
		}
	}
}


/**** Event handling ****/

/* internal routines */

static void od_emil_button_position (GtkMenu *menu, gint *xp, gint *yp, gpointer userdata) {
	ODEmilButton *button;
	GtkWidget *item, *active = NULL;
	GList *list, *list2;
	gint x,y, width,height;
	gint scrwidth,scrheight;
	gint btnx,btny, btnwidth,btnheight;
	gint itmwidth, itmheight;
	gint i;
	
	g_return_if_fail (userdata != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(userdata));
	button = OD_EMIL_BUTTON(userdata);
	g_return_if_fail (GTK_WIDGET(menu) == button->menu);

	width =  GTK_WIDGET(menu)->requisition.width;
	height = GTK_WIDGET(menu)->requisition.height;

	scrwidth  = gdk_screen_width();
	scrheight = gdk_screen_height();

	if (button->nth) {
		/*	the menu appears with the mouse button centered at the current (first)
			item, and the menu is constrained to the button width-wise.
		*/
		list = GTK_MENU_SHELL(menu)->children;
		if (list==NULL)	goto no_active;
		
		list2 = g_list_nth(list, button->nth - 1);
		if (list2 == NULL) goto no_active;

		if (GTK_BIN(list2->data)->child)
			active = list2->data;

		if (active == NULL) goto no_active;

		gdk_window_get_origin(GTK_WIDGET(button)->window, &btnx, &btny);
		btnwidth = GTK_WIDGET(button)->allocation.width;
		btnheight = GTK_WIDGET(button)->allocation.height;

		itmwidth = active->requisition.width;
		itmheight = active->requisition.height;

		x = *xp - width/2 - 1;
		y = *yp - itmheight/2 - 3;

		if (itmheight + 2 < btnheight) {
			if (y < btny) y = btny;
			else if (y+itmheight > btny+btnheight) y = btny + btnheight - itmheight;
		} else {
			y = btny;
		}

		if (width < btnwidth) {
			if (x<btnx) x = btnx;
			else if (x+width > btnx+btnwidth) x = btnx + btnwidth - width;
		} else {
			if (x > btnx) x = btnx;
			else if (x+width < btnx+btnwidth) x = btnx + btnwidth - width;
		}

		while (list) {
			item = list->data;

			if (item == active)
				break;
			
			if (GTK_WIDGET_VISIBLE(item))
				y -= item->requisition.height;
	
			list = list->next;
		}
	} else {
	  no_active:
		x = *xp;
		y = *yp;

		if (x+width > scrwidth) x -= width - 1;
		if (x<0) x=0;
		if (y+height > scrheight) y -= height - 1;
		if (y<0) y=0;
	}

	if (y+height > scrheight) y = scrheight - height;
	if (y<0) y = 0;
	if (x+width > scrwidth) x = scrwidth - width;
	if (x<0) x = 0;

	*xp = x;
	*yp = y;
}


static void od_emil_button_deactivate (GtkMenuShell *menu_shell, ODEmilButton *button) {
	g_return_if_fail (button != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(button));
	g_return_if_fail (GTK_WIDGET(menu_shell) == button->menu);

  #if DEBUG
	puts("od_emil_button_deactivate()");
  #endif
}


static void od_emil_button_popup (ODEmilButton *button, GdkEvent *event) {
	GtkWidget *item, *widget;
	GList *list;
	guint16 mb;

  #if DEBUG	
	puts("enter od_emil_button_popup()");
  #endif

	if (!button->menu)
		return;

	/* go */
	mb = 0;
	if (event->type == GDK_BUTTON_PRESS)
		mb = ((GdkEventButton *) event)->button;

	if (button->oldstyle && button->nth) {
	  /*
		gtk_widget_set_style(GTK_WIDGET(button->menu), gtk_widget_get_style(GTK_WIDGET(button)));
	  */
		col_set_style (GTK_WIDGET(button->menu), gtk_widget_get_style(GTK_WIDGET(button)));
	}
	
	gtk_menu_popup (GTK_MENU (button->menu), NULL, NULL, od_emil_button_position, button,
					mb, ((GdkEventButton *)event)->time);
}


static void od_emil_button_set (ODEmilButton *button, guint index) {
	GtkWidget *widget;
	GtkWidget *oldwidget;
	GtkRequisition child_requisition;

	g_return_if_fail (button != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(button));
	g_return_if_fail (index < OD_EMIL_BUTTON_MAX_CHOICES);

  #if DEBUG
	printf("od_emil_button_set(0x%08x, %d)\n", button, index);
  #endif

	widget = button->choices[index].widget;
	
	oldwidget = GTK_BIN(button)->child;
	if (oldwidget != widget) {
		if (oldwidget) {
			gtk_widget_ref(oldwidget);
			gtk_container_remove (GTK_CONTAINER(button), oldwidget);
		  #if DEBUG
			printf("oldwidget->ref_count = %d\n", GTK_OBJECT(oldwidget)->ref_count);
		  #endif
		}

		if (widget) {
			if (GTK_WIDGET(button)->state != widget->state)
				gtk_widget_set_state (widget, GTK_WIDGET(button)->state);
			
			if (widget->parent) {
				gtk_widget_reparent (widget, GTK_WIDGET(button));
			} else {
				gtk_container_add (GTK_CONTAINER(button), widget);
				gtk_widget_unref(widget);
			}
			
			gtk_widget_set_style(GTK_WIDGET(button), gtk_widget_get_style(widget));

		  #if DEBUG
			printf("widget->ref_count = %d\n", GTK_OBJECT(widget)->ref_count);
		  #endif
		} else if (button->oldstyle && button->oldstyle != gtk_widget_get_style(oldwidget)) {
			gtk_widget_set_style(GTK_WIDGET(button), button->oldstyle);
		}
	}
	if (GTK_WIDGET_DRAWABLE (button))
		gtk_widget_queue_draw (GTK_WIDGET (button));
}


static void od_emil_button_select (GtkMenuItem *menu_item, ODEmilButtonChoice *choice) {
	ODEmilButton *button;

	g_return_if_fail(choice != NULL);
	g_return_if_fail(OD_IS_EMIL_BUTTON(button));

  #if DEBUG
	puts("Option selected in menu");
  #endif
}


/* Event routines */

/* from GtkOptionMenu, don't know if it is necessary */
static gint od_emil_button_expose (GtkWidget *widget, GdkEventExpose *event) {
	GtkWidget *child;
	GdkEventExpose child_event;
	
	g_return_val_if_fail (widget != NULL, FALSE);
	g_return_val_if_fail (OD_IS_EMIL_BUTTON(widget), FALSE);
	g_return_val_if_fail (event != NULL, FALSE);
	
	if (GTK_WIDGET_DRAWABLE (widget)) {
		od_emil_button_paint (widget, &event->area);

		child = GTK_BIN (widget)->child;
		child_event = *event;
		if (child && GTK_WIDGET_NO_WINDOW (child) && gtk_widget_intersect (child, &event->area, &child_event.area))
			gtk_widget_event (child, (GdkEvent*) &child_event);
	}	
	return FALSE;
}


static void od_emil_button_enter (GtkButton *button) {
	GtkStateType new_state;
	ODEmilButton *emil_button;
	
	g_return_if_fail (button != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON (button));
	emil_button = OD_EMIL_BUTTON(button);
	
	new_state = (emil_button->button ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT);

	if (emil_button->button > 1)
		od_emil_button_set(OD_EMIL_BUTTON(button), OD_EMIL_BUTTON_SECONDARY);
	
	if (GTK_WIDGET_STATE (button) != new_state) {
		gtk_widget_set_state (GTK_WIDGET (button), new_state);
		gtk_widget_queue_draw (GTK_WIDGET (button));
	}
}


static void od_emil_button_leave (GtkButton *button) {
	ODEmilButton *emil_button;
	
	g_return_if_fail (button != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON (button));
	emil_button = OD_EMIL_BUTTON(button);

	if (emil_button->button > 1)
		od_emil_button_set(OD_EMIL_BUTTON(button), OD_EMIL_BUTTON_PRIMARY);

	if (GTK_WIDGET_STATE (button) != GTK_STATE_NORMAL) {
		gtk_widget_set_state (GTK_WIDGET (button), GTK_STATE_NORMAL);
		gtk_widget_queue_draw (GTK_WIDGET (button));
	}
}


static gint od_emil_button_button_release (GtkWidget *widget, GdkEventButton *event) {
	ODEmilButton *button;
	ODEmilButtonChoice *choice;
	GtkStateType state_type;
	guint8 mouse;

	g_return_val_if_fail (widget != NULL, FALSE);
	g_return_val_if_fail (OD_IS_EMIL_BUTTON (widget), FALSE);
	g_return_val_if_fail (event != NULL, FALSE);
	button = OD_EMIL_BUTTON (widget);

	mouse = event->button;

  #if DEBUG
	printf("event->state = 0x%04x\n", event->state);
  #endif

	if (event->type != GDK_BUTTON_RELEASE || mouse > 2)
		return FALSE;

	if (mouse==1 && (GdkModifierType)(event->state) & GDK_SHIFT_MASK)
		mouse = 2;

	if (mouse != button->button)
		return FALSE;

	gtk_grab_remove(widget);
	od_emil_button_set(button, OD_EMIL_BUTTON_PRIMARY);

	button->button = 0;
	GTK_BUTTON(button)->button_down = 0;
	
	state_type = GTK_STATE_NORMAL;
	if (GTK_BUTTON(button)->in_button) {
		choice = &(button->choices[mouse - 1]);
		if (choice->widget || button->config) {
		  #if DEBUG
			printf("clicked button nr %d\n", button->button);
		  #endif
			gtk_signal_emit(GTK_OBJECT(button), emil_button_signals[ACTIVATE], choice->user_data, mouse-1);
		}
		state_type = GTK_STATE_PRELIGHT;
	}

	if (GTK_WIDGET_STATE(widget) != state_type) {
		gtk_widget_set_state(widget, state_type);
		gtk_widget_draw (widget, NULL);
	} else {
	  #if DEBUG
		puts("widget not active!");
	  #endif
	}

	return TRUE;
}


static gint od_emil_button_button_press (GtkWidget *widget, GdkEventButton *event) {
	ODEmilButton *button;
	guint8 mouse;
	
	g_return_val_if_fail (widget != NULL, FALSE);
	g_return_val_if_fail (OD_IS_EMIL_BUTTON (widget), FALSE);
	g_return_val_if_fail (event != NULL, FALSE);
	button = OD_EMIL_BUTTON(widget);

	mouse = event->button;

	if (event->type != GDK_BUTTON_PRESS || mouse > 3)
		return FALSE;

	if (mouse==1 && (GdkModifierType)(event->state & 0x0005) & GDK_SHIFT_MASK)
		mouse = 2;

	if (button->button && mouse != button->button)
		return TRUE;

	if (mouse >= 3) {
		if (button->menu && !button->config) {
			od_emil_button_popup(button, (GdkEvent *)event);
			return TRUE;
		}
	} else {
		if (button->config) {
			if (mouse == 2 && button->choices[1].widget)
				od_emil_button_set(button, OD_EMIL_BUTTON_SECONDARY );
		} else {
			if (   !button->config
				&& (   (mouse == 1 && button->choices[OD_EMIL_BUTTON_PRIMARY].widget == NULL)
					|| (mouse != 1 && button->choices[OD_EMIL_BUTTON_SECONDARY].widget == NULL)))
			{
				return FALSE;
			}
			od_emil_button_set(button, mouse==1 ? OD_EMIL_BUTTON_PRIMARY : OD_EMIL_BUTTON_SECONDARY );
		}
		
		button->button = mouse;

		if (!GTK_WIDGET_HAS_FOCUS (widget))
			gtk_widget_grab_focus (widget);

		if (GTK_WIDGET_STATE(widget) != GTK_STATE_ACTIVE) {
			gtk_widget_set_state (widget, GTK_STATE_ACTIVE);
			gtk_widget_draw (widget, NULL);
		}
		gtk_grab_add(widget);

		GTK_BUTTON(button)->button_down = 1;
		return TRUE;
	}
	return FALSE;
}


static void od_emil_button_detacher (GtkWidget *widget, GtkMenu *menu) {
	ODEmilButton *button;
	
	g_return_if_fail (widget != NULL);
	g_return_if_fail (OD_IS_EMIL_BUTTON(widget));
	
	button = OD_EMIL_BUTTON(widget);
	g_return_if_fail (button->menu == (GtkWidget *) menu);

	if (button->nth)
		col_restore_style (GTK_WIDGET(menu));
	button->menu = NULL;
}


void od_emil_button_config_mode (ODEmilButton *button, gboolean enabled) {
	g_return_if_fail(button != NULL);
	g_return_if_fail(OD_IS_EMIL_BUTTON(button));
	
	if (enabled) {
		button->config |= 0x1;
   	} else {
		button->config = 0;
	}
}

void od_emil_button_config_select (ODEmilButton *button, gboolean enabled) {
	g_return_if_fail(button != NULL);
	g_return_if_fail(OD_IS_EMIL_BUTTON(button));

	button->config = button->config&0x1 | (enabled ? 0x2 : 0x00);

	if (GTK_WIDGET_DRAWABLE (button))
		gtk_widget_queue_draw (GTK_WIDGET (button));
}


void od_emil_button_set_colors (ODEmilButton *button, guint index,
								const GdkColor *fg, const GdkColor *bg)
{
	GtkStyle *newstyle;
	GtkWidget *widget;
	
	g_return_if_fail(button != NULL);
	g_return_if_fail(OD_IS_EMIL_BUTTON(button));
	g_return_if_fail(index < OD_EMIL_BUTTON_MAX_CHOICES);

	widget = button->choices[index].widget;
	
	if (fg || bg) {
	  #if DEBUG
		puts("od_emil_button_set_colors: setting colors\n");
	  #endif
		if (!widget) {
		  #if DEBUG
			puts("od_emil_button_set_colors: creating new empty label\n");
		  #endif
			widget = gtk_label_new(" ");
			gtk_misc_set_alignment (GTK_MISC (widget), 0.5, 0.5);
			od_emil_button_set_widget(button, index, widget, button->choices[index].user_data);
		}

		newstyle = col_make_style(button->oldstyle, fg, bg);
		if (index == OD_EMIL_BUTTON_SECONDARY) {
			newstyle->fg[GTK_STATE_ACTIVE] = newstyle->fg[GTK_STATE_NORMAL];
			newstyle->bg[GTK_STATE_ACTIVE] = newstyle->bg[GTK_STATE_NORMAL];
		}
		gtk_widget_set_style(widget, newstyle);
	} else if (widget && button->oldstyle) {
	  #if DEBUG
		puts("od_emil_button_set_colors: resetting widget style to button style");
	  #endif
		gtk_widget_set_style(widget, button->oldstyle);
	}
	
	if (widget && index==OD_EMIL_BUTTON_PRIMARY)
		gtk_widget_set_style(GTK_WIDGET(button), gtk_widget_get_style(widget));
	
  #if DEBUG
	puts("od_emil_button_set_colors: done\n");
  #endif
}

void od_emil_button_set_text (ODEmilButton *button, guint index, const gchar *text) {
	GtkWidget *widget;
	GtkStyle *style;
	
	g_return_if_fail(button != NULL);
	g_return_if_fail(OD_IS_EMIL_BUTTON(button));
	g_return_if_fail(index < OD_EMIL_BUTTON_MAX_CHOICES);

	widget = button->choices[index].widget;
	if (widget) {
		if (GTK_IS_LABEL(widget)) {
		  #if DEBUG
			puts("od_emil_button_set_text(): setting label text on old label widget");
		  #endif
			gtk_label_set_text(GTK_LABEL(widget), text);
			if (GTK_WIDGET(button)->parent)
				gtk_widget_queue_resize (GTK_WIDGET(button));
			if (GTK_WIDGET_DRAWABLE(button))
				gtk_widget_queue_draw (GTK_WIDGET(button));
			return;
		} else {
		  #if DEBUG
			puts("od_emil_button_set_text(): widget not label, away it goes, in comes a new one with the old widgets' style");
		  #endif
			gtk_widget_ensure_style(widget);
			style = gtk_widget_get_style(widget);
			od_emil_button_remove_widget(button, index);
			
			widget = gtk_label_new(text);
			gtk_widget_set_style(widget, style);
		}
	} else {
	  #if DEBUG
		puts("od_emil_button_set_text(): creating new label");
	  #endif
		widget = gtk_label_new(text);
	}
	gtk_misc_set_alignment (GTK_MISC (widget), 0.5, 0.5);
	od_emil_button_set_widget(button, index, widget, button->choices[index].user_data);
}

gpointer od_emil_button_get_user_data (const ODEmilButton *button, guint index) {
	g_return_if_fail(button != NULL);
	g_return_if_fail(OD_IS_EMIL_BUTTON(button));
	g_return_if_fail(index < OD_EMIL_BUTTON_MAX_CHOICES);

	return button->choices[index].user_data;
}

void od_emil_button_set_user_data (ODEmilButton *button, guint index, const gpointer user_data) {
	g_return_if_fail(button != NULL);
	g_return_if_fail(OD_IS_EMIL_BUTTON(button));
	g_return_if_fail(index < OD_EMIL_BUTTON_MAX_CHOICES);

	button->choices[index].user_data = user_data;;
}


