/****************************************************************************
 *	metagtk.c
 *
 *	gtk graphic device : widget for graphic output
 *
 ****************************************************************************/
#include <stdio.h>
#include <math.h>
#include <string.h>

#include "graphics.h"
#include "metagtk.h"
#include "sysdep.h"


#define META_WIDTH_DEFAULT	100
#define	META_HEIGHT_DEFAULT	100


static int oldst=-1;
static int oldwidth=-1;
static int oldcolor=-1;

#define FONT_PATTERN "-*-helvetica-medium-r-normal-*-*-%d-*-*-p-*-iso8859-1"
static int font_size=12;

/*
 *	method called by the metafile driver for Gtk
 */
static void gtk_meta_begin (void *p);
static void gtk_meta_end (void *p);
static void gtk_meta_clear (void *p);
static void gtk_meta_clip (void *data, double c, double r, double c1, double r1);
static void gtk_meta_line (void *p, double c, double r, double c1, double r1, int color, int style, int width);
static void gtk_meta_marker (void *p, double c, double r, int color, int type);
static void gtk_meta_fill (void *p, double c[], int st, int n, int connect[]);
static void gtk_meta_fillh (void *p, double c[], double hue, int color, int connect);
static void gtk_meta_bar (void *p, double c, double r, double c1, double r1, double hue, int color, int connect);
static void gtk_meta_bar1 (void *p, double c, double r, double c1, double r1, int color, int connect);
static void gtk_meta_text (void *p, double c, double r, char *text, int color, int alignment);
static void gtk_meta_vtext (void *p, double c, double r, char *text, int color, int alignment);
static void gtk_meta_vutext (void *p, double c, double r, char *text, int color, int alignment);
static void gtk_meta_scale (void *p, double s);

/*
 *	events methods
 */
static void gtk_meta_realize (GtkWidget *widget);
static void gtk_meta_unrealize (GtkWidget *widget);
static void gtk_meta_size_request (GtkWidget *widget, GtkRequisition *requisition);
static void gtk_meta_size_allocate (GtkWidget *widget, GtkAllocation *allocation);
static gint gtk_meta_expose (GtkWidget *widget, GdkEventExpose *event);
static gint gtk_meta_button_press (GtkWidget *widget, GdkEventButton *event);

/*****************************************************************************
 *	Initialization / destruction of the widget
 *
 *****************************************************************************/

static GtkWidgetClass *parent_class = NULL;

static void gtk_meta_class_init	(GtkMetaClass *klass);
static void gtk_meta_init		(GtkMeta      *term);
static void gtk_meta_destroy	(GtkObject    *object);

GType gtk_meta_get_type()
{
	static GType meta_type = 0;

	if (!meta_type)
	{
		GTypeInfo meta_info =
		{
			sizeof (GtkMetaClass),
			NULL,
			NULL,
			(GClassInitFunc) gtk_meta_class_init, 
			NULL,
			NULL,
			sizeof (GtkMeta),
			0,
			(GInstanceInitFunc) gtk_meta_init
		};

		meta_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkMeta",
                                         	&meta_info, 0);
	}

	return meta_type;
}

/*
 *	init of new signals and virtual methods
 */
static void gtk_meta_class_init(GtkMetaClass *klass)
{
	GtkObjectClass *object_class = (GtkObjectClass*)klass;
	GtkWidgetClass *widget_class = (GtkWidgetClass*)klass;
	
	/*
	 *	save a copy of parent class structure to keep access to
	 *	its methods
	 */
	parent_class = gtk_type_class (gtk_widget_get_type ());

	/*
	 *	defining virtual methods
	 */
	object_class->destroy = gtk_meta_destroy;

	widget_class->realize = gtk_meta_realize;
	widget_class->unrealize = gtk_meta_unrealize;
	widget_class->size_request = gtk_meta_size_request;
	widget_class->size_allocate = gtk_meta_size_allocate;
	widget_class->expose_event = gtk_meta_expose;
	widget_class->button_press_event = gtk_meta_button_press;
}

/*
 *	init of object parameters, create subwidgets
 */
static void gtk_meta_init(GtkMeta *meta)
{
	meta->width = meta->height = 0;
	
	meta->font = NULL;
	meta->cmap = NULL;
	meta->colors = NULL;
	meta->gc = meta->stipplegc = NULL;

	meta->cursor		= NULL;
	
	meta->draw			= NULL;
	meta->pixmap		= NULL;
	meta->playing		= 0;
	
	meta->dev.data		= NULL;
	meta->dev.begin		= gtk_meta_begin;
	meta->dev.end		= gtk_meta_end;
	meta->dev.clear		= gtk_meta_clear;
	meta->dev.clip		= gtk_meta_clip;
	meta->dev.line		= gtk_meta_line;
	meta->dev.marker	= gtk_meta_marker;
	meta->dev.bar		= gtk_meta_bar;
	meta->dev.bar1		= gtk_meta_bar1;
	meta->dev.fill		= gtk_meta_fill;
	meta->dev.fillh		= gtk_meta_fillh;
	meta->dev.text		= gtk_meta_text;
	meta->dev.vtext		= gtk_meta_vtext;
	meta->dev.vutext	= gtk_meta_vutext;
	meta->dev.scale		= gtk_meta_scale;

	meta->x = 0.0;
	meta->y = 0.0;
}

/*
 *	GtkObject destroy method
 */
static void gtk_meta_destroy (GtkObject *object)
{
	GtkMeta *meta;

	g_return_if_fail (object != NULL);
	g_return_if_fail (GTK_IS_META (object));

	meta = GTK_META (object);
	
	g_free(meta->colors);
	
	gdk_cursor_destroy(meta->cursor);
	
	gdk_font_unref (meta->font);

	/*
	 *	call widget class destroy method
	 */
	if (GTK_OBJECT_CLASS (parent_class)->destroy)
		(* GTK_OBJECT_CLASS (parent_class)->destroy)(object);
}

/****************************************************************************
 *	meta widget
 *
 *	public interface
 *
 ****************************************************************************/

GtkWidget* gtk_meta_new(gint width, gint height)
{
	GtkMeta *meta;
	
	g_return_val_if_fail(width>0 && height>0,NULL);

	meta = gtk_type_new (gtk_meta_get_type ());

	meta->width = width;
	meta->height = height;
	meta->dev.data = meta;

	return GTK_WIDGET (meta);
}

metadevice * gtk_meta_get_device(GtkWidget *widget)
{
	GtkMeta *meta;
	
	g_return_val_if_fail(GTK_IS_META(widget),NULL);
	meta = GTK_META(widget);
	
	return &(meta->dev);
}

void gtk_meta_update_lines(GtkWidget *widget)
{
	GtkMeta *meta;
	int newsize;
	
	g_return_if_fail(GTK_IS_META(widget));
	meta = GTK_META(widget);

	newsize = widget->allocation.height/getmetalines();
	if (newsize!=font_size) {
		if (meta->font) gdk_font_unref(meta->font);
		font_size = newsize;
		meta->font = gdk_font_load (g_strdup_printf(FONT_PATTERN,font_size*10));
		if (meta->font) {
			setmetacharwidth(gdk_char_width(meta->font,'m')*1024l/widget->allocation.width);
			setmetacharheight((meta->font->ascent + meta->font->descent)*1024l/widget->allocation.height);
		}
		else
			fprintf(stderr,"the font %s can't be loaded\n",g_strdup_printf(FONT_PATTERN,font_size*10));
	}
}

void gtk_meta_update_colors(GtkWidget *widget)
{
	GtkMeta *meta;
	int i;
	
	g_return_if_fail(GTK_IS_META(widget));
	meta = GTK_META(widget);

	for (i=0;i<MAX_COLORS;i++) {
		gdk_colormap_free_colors(meta->cmap,&(meta->colors[i]),1);
		meta->colors[i].red   = ((gushort)getmetacolor(0,i))<<8;
		meta->colors[i].green = ((gushort)getmetacolor(1,i))<<8;
		meta->colors[i].blue  = ((gushort)getmetacolor(2,i))<<8;
		gdk_color_alloc(meta->cmap,&(meta->colors[i]));
	}
}

/****************************************************************************
 *	meta widget
 *
 *	event interface
 *
 ****************************************************************************/

static void gtk_meta_realize (GtkWidget *widget)
{
	GtkMeta *meta;
	GdkWindowAttr attributes;
	gint attributes_mask;
	int i;

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

	GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
	meta = GTK_META (widget);

	attributes.x = widget->allocation.x;
	attributes.y = widget->allocation.y;
	attributes.width = widget->allocation.width;
	attributes.height = widget->allocation.height;
	attributes.wclass = GDK_INPUT_OUTPUT;
	attributes.window_type = GDK_WINDOW_CHILD;
	attributes.event_mask = gtk_widget_get_events (widget)
			| GDK_EXPOSURE_MASK
			| GDK_BUTTON_PRESS_MASK;

	attributes.visual = gtk_widget_get_visual (widget);
	attributes.colormap = meta->cmap = gtk_widget_get_colormap (widget);
	attributes.cursor = meta->cursor = gdk_cursor_new(GDK_CROSSHAIR);

	attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_CURSOR;

	/* main window */
	widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
				   &attributes, attributes_mask);
	widget->style = gtk_style_attach (widget->style, widget->window);
	gdk_window_set_user_data (widget->window, widget);
	gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);

	gdk_window_set_background (widget->window, &widget->style->white);
	
	meta->stipplegc = gdk_gc_new(widget->window);
	meta->gc = gdk_gc_new(widget->window);
	gdk_gc_set_background(meta->gc,&(widget->style->white));
	gdk_gc_set_foreground(meta->gc,&(widget->style->black));
	
	meta->colors = g_new(GdkColor,MAX_COLORS);
	
	for (i=0;i<MAX_COLORS;i++) {
		meta->colors[i].red   = ((gushort)getmetacolor(0,i))<<8;
		meta->colors[i].green = ((gushort)getmetacolor(1,i))<<8;
		meta->colors[i].blue  = ((gushort)getmetacolor(2,i))<<8;
		gdk_color_alloc(meta->cmap,&(meta->colors[i]));
	}
	
	font_size = widget->allocation.height/getmetalines();
	meta->font = gdk_font_load (g_strdup_printf(FONT_PATTERN,font_size*10));
	setmetacharwidth(gdk_char_width(meta->font,'m')*1024l/widget->allocation.width);
	setmetacharheight((meta->font->ascent + meta->font->descent)*1024l/widget->allocation.height);

	setmetawidth(widget->allocation.width);
	setmetaheight(widget->allocation.height);
	
	meta->pixmap = gdk_pixmap_new(widget->window,widget->allocation.width,widget->allocation.height,-1);
	gdk_draw_rectangle(meta->pixmap,widget->style->white_gc,1,0,0,-1,-1);

	meta->draw = widget->window;
}

static void gtk_meta_unrealize (GtkWidget *widget)
{
	GtkMeta *meta;

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

	GTK_WIDGET_UNSET_FLAGS (widget, GTK_REALIZED);
	
	meta = GTK_META (widget);
	
	gdk_pixmap_unref(meta->pixmap);
	
	gdk_gc_destroy(meta->gc);
	gdk_gc_destroy(meta->stipplegc);
	
	if (GTK_WIDGET_CLASS (parent_class)->unrealize)
		(*GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
}

/*
 *	size_request : set the minimum widget size
 */
static void gtk_meta_size_request (GtkWidget *widget, GtkRequisition *requisition)
{
	GtkMeta *meta;

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

	meta = GTK_META (widget);
	
	if (meta->width && meta->height) {
		requisition->width = meta->width;
		requisition->height = meta->height;
		meta->width = meta->height = 0;
	} else {
		requisition->width = META_WIDTH_DEFAULT;
		requisition->height = META_HEIGHT_DEFAULT;
	}
}

/*
 *	size_allocate : set the actual widget size
 */
static void gtk_meta_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
{
	GtkMeta *meta;
	static short count = 1;
	
	g_return_if_fail (widget != NULL);
	g_return_if_fail (GTK_IS_META (widget));
	g_return_if_fail (allocation != NULL);

	widget->allocation = *allocation;

	if (GTK_WIDGET_REALIZED(widget))
	{
		int newsize;
		GdkRectangle r;
		
		if (count == 2) {
			gtk_widget_set_size_request(widget, META_WIDTH_DEFAULT, META_HEIGHT_DEFAULT);
			count = 0;
		}
		
		if (count == 1) count = 2;
			
		meta = GTK_META(widget);

		gdk_window_move_resize(widget->window,
							allocation->x,
							allocation->y,
							allocation->width,
							allocation->height);
		if (meta->pixmap)
			gdk_pixmap_unref(meta->pixmap);
		
		 meta->pixmap = gdk_pixmap_new(widget->window,
							widget->allocation.width,
							widget->allocation.height,
							-1);
		gdk_draw_rectangle (meta->pixmap,
							widget->style->white_gc,
							TRUE,
							0, 0,
							widget->allocation.width,
							widget->allocation.height);

		setmetawidth(widget->allocation.width);
		setmetaheight(widget->allocation.height);
		r.x = allocation->x;
		r.y = allocation->y;
		r.width = allocation->width;
		r.height = allocation->height;
		gdk_gc_set_clip_rectangle(meta->gc, &r);
		
		newsize = widget->allocation.height/getmetalines();
		if (newsize!=font_size) {
			if (meta->font) gdk_font_unref(meta->font);
			font_size = newsize;
			meta->font = gdk_font_load (g_strdup_printf(FONT_PATTERN,font_size*10));
			if (meta->font) {
				setmetacharwidth(gdk_char_width(meta->font,'m')*1024l/widget->allocation.width);
				setmetacharheight((meta->font->ascent + meta->font->descent)*1024l/widget->allocation.height);
			}
			else
				fprintf(stderr,"the font %s can't be loaded\n",g_strdup_printf(FONT_PATTERN,font_size*10));
		}
	}
}

static gint gtk_meta_expose(GtkWidget *widget, GdkEventExpose *event)
{
	if (event->count==0) {
		GtkMeta *meta = GTK_META(widget);
	
		if (!meta->playing) {
			meta->draw = meta->pixmap;
			playmeta();
			gdk_draw_pixmap(widget->window,meta->gc,meta->pixmap,0,0,0,0,-1,-1);
			meta->draw = widget->window;
		}
	}
	return FALSE;
}

static gint gtk_meta_button_press (GtkWidget *widget, GdkEventButton *event)
{
	GtkMeta * meta;
	
	g_return_val_if_fail (widget != NULL, FALSE);
	g_return_val_if_fail (GTK_IS_META (widget), FALSE);
	g_return_val_if_fail (event != NULL, FALSE);

	meta = GTK_META(widget);

	meta->x = (double)(((event)->x)*1024.0/widget->allocation.width);
	meta->y	= (double)(((event)->y)*1024.0/widget->allocation.height);
	
	return FALSE;
}

/****************************************************************************
 *	metagtk.c
 *
 *	metafile interface
 *
 ****************************************************************************/

#define col(c) ((int)(((c)*widget->allocation.width)/1024.0))

#define row(r) ((int)(((r)*widget->allocation.height)/1024.0))

static void setcolor (GtkMeta *meta, int c)
{
	if (c!=oldcolor)
	{
		gdk_gc_set_foreground(meta->gc,&(meta->colors[c]));
		oldcolor=c;
	}
}

/* hsv_to_rgb
 *	converts hsv color representation to rgb representation.
 *	taken from the gtk_color_selection box.
 */
static void hsv_to_rgb (double h,double s,double v,double *r,double *g,double *b)
{
	int i;
	double f, w, q, t;

	if (s == 0.0) s = 0.000001;

	if (h == -1.0) {
		*r = v;
		*g = v;
		*b = v;
	} else {
		if (h == 360.0) h = 0.0;
		h = h / 60.0;
		i = (int)h;
		f = h - i;
		w = v * (1.0 - s);
		q = v * (1.0 - (s * f));
		t = v * (1.0 - (s * (1.0 - f)));

		switch (i) {
			case 0:
				*r = v;
				*g = t;
				*b = w;
				break;
			case 1:
				*r = q;
				*g = v;
				*b = w;
				break;
			case 2:
				*r = w;
				*g = v;
				*b = t;
				break;
			case 3:
				*r = w;
				*g = q;
				*b = v;
				break;
			case 4:
				*r = t;
				*g = w;
				*b = v;
				break;
			case 5:
				*r = v;
				*g = w;
				*b = q;
				break;
		}
    }
}

static void sethue (GtkMeta *meta, double hue, int ncol)
{
	GdkColor c;
	int r, g, b;
	
	if(ncol) {
		r = 2*hue*(128+((meta->colors[ncol].red)>>8)/2);
		g = 2*hue*(128+((meta->colors[ncol].green)>>8)/2);
		b = 2*hue*(128+((meta->colors[ncol].blue)>>8)/2);
	} else {
		double cr,cg,cb;
		hsv_to_rgb((1.0-hue)*255.0,0.5,0.9,&cr,&cg,&cb);
		r = (int)(255.0*cr);
		g = (int)(255.0*cg);
		b = (int)(255.0*cb);
		
	}
	c.red	= r>255 ? 255<<8:((gushort)(r))<<8;
	c.green	= g>255 ? 255<<8:((gushort)(g))<<8;
	c.blue	= b>255 ? 255<<8:((gushort)(b))<<8;
/*
	c.red	= ((gushort)(2*hue*(128+((meta->colors[ncol].red)>>8)/2)))<<8;
	c.green	= ((gushort)(2*hue*(128+((meta->colors[ncol].green)>>8)/2)))<<8;
	c.blue	= ((gushort)(2*hue*(128+((meta->colors[ncol].blue)>>8)/2)))<<8;*/
	gdk_color_alloc(meta->cmap,&c);
	gdk_gc_set_foreground(meta->stipplegc,&c);
}

static void setline (GtkMeta *meta, int w, int st)
{
	if (w==1) w=0;
	if (oldwidth==w && oldst==st) return;
	oldst=st;
	switch (st)
	{	case line_dotted :
		case line_dashed :
			st=GDK_LINE_ON_OFF_DASH;
			break;
		default :
			st=GDK_LINE_SOLID;
			break;
	}
	gdk_gc_set_line_attributes(meta->gc,w,st,GDK_CAP_ROUND,GDK_JOIN_ROUND);
	oldwidth=w;
}

static void gtk_meta_begin (void *p)
{
	GtkMeta *meta = (GtkMeta*)p;
//	GtkWidget *widget = GTK_WIDGET(meta);
//	gdk_flush();
	meta->draw = meta->pixmap;
	meta->playing = 1;
}

static void gtk_meta_end (void *p)
{
	GtkMeta *meta = (GtkMeta*)p;
	GtkWidget *widget = GTK_WIDGET(meta);

	meta->playing = 0;
	meta->draw = widget->window;
}

static void gtk_meta_clear (void *p)
{
	GtkMeta *meta = (GtkMeta*)p;
	GtkWidget *widget = GTK_WIDGET(meta);
	
	if (meta->playing)
		gdk_draw_pixmap(widget->window,meta->gc,meta->pixmap,0,0,0,0,-1,-1);
	
	gdk_draw_rectangle(meta->draw,widget->style->white_gc,1,0,0,-1,-1);
}

static void gtk_meta_clip (void *data, double c, double r, double c1, double r1)
{
	GtkMeta *meta = (GtkMeta*)data;
	GtkWidget *widget = GTK_WIDGET(meta);
	GdkRectangle rect;
	
	rect.x = col(c);
	rect.y = row(r);
	rect.width = col(c1)-rect.x+1;
	rect.height = row(r1)-rect.y+1;
	
	gdk_gc_set_clip_rectangle(meta->gc, &rect);
}


static void gtk_meta_line (void *p, double c, double r, double c1, double r1, int color, int style, int width)
/***** gline
	draw a line.
*****/
{
	GtkMeta *meta = (GtkMeta*)p;
	GtkWidget *widget = GTK_WIDGET(meta);
	
	if (style==line_none)
		setcolor(meta,0);
	else
		setcolor(meta,color);
	setline(meta,width,style);
	
	gdk_draw_line(meta->draw,meta->gc,col(c),row(r),col(c1),row(r1));
	
	setline(meta,1,line_solid);
	if (style==line_arrow)
	{
		double sin20 = 0.3420201433;
		double ah = 14.0;
		double dx = c1 - c;
		double dy = r1 - r;
		double norme = sqrt(dx*dx+dy*dy);
		double cs = dx/norme;
		double sn = dy/norme;
		GdkPoint p[3];
		
		p[0].x = col(c+norme*cs-ah*(cs+sn*sin20));
		p[0].y = row(r+norme*sn-ah*(sn-cs*sin20));
		p[1].x = col(c1);
		p[1].y = row(r1);
		p[2].x = col(c+norme*cs-ah*(cs-sn*sin20));
		p[2].y = row(r+norme*sn-ah*(sn+cs*sin20));

		gdk_draw_polygon(meta->draw,meta->gc,1,p,3);
	}
}

static void gtk_meta_marker (void *p, double c, double r, int color, int type)
/***** gmarker
	plot a single marker on screen.
*****/
{
	GtkMeta *meta = (GtkMeta*)p;
	GtkWidget *widget = GTK_WIDGET(meta);

	setcolor(meta,color);
	setline(meta,1,line_solid);
	switch(type) {
		case marker_dot :
			gdk_draw_point(meta->draw,meta->gc,col(c),row(r));
			break;
		case marker_plus :	
			gdk_draw_line(meta->draw,meta->gc,col(c+10),row(r),col(c-10),row(r));
			gdk_draw_line(meta->draw,meta->gc,col(c),row(r-10),col(c),row(r+10));
			break;
		case marker_square :
		case marker_circle :
			gdk_draw_line(meta->draw,meta->gc,col(c+10),row(r-10),col(c+10),row(r+10));
			gdk_draw_line(meta->draw,meta->gc,col(c+10),row(r+10),col(c-10),row(r+10));
			gdk_draw_line(meta->draw,meta->gc,col(c-10),row(r+10),col(c-10),row(r-10));
			gdk_draw_line(meta->draw,meta->gc,col(c-10),row(r-10),col(c+10),row(r-10));
			break;
		case marker_diamond :
			gdk_draw_line(meta->draw,meta->gc,col(c),row(r-10),col(c+10),row(r));
			gdk_draw_line(meta->draw,meta->gc,col(c+10),row(r),col(c),row(r+10));
			gdk_draw_line(meta->draw,meta->gc,col(c),row(r+10),col(c-10),row(r));
			gdk_draw_line(meta->draw,meta->gc,col(c-10),row(r),col(c),row(r-10));
			break;
		case marker_star :
			gdk_draw_line(meta->draw,meta->gc,col(c+10),row(r),col(c-10),row(r));
			gdk_draw_line(meta->draw,meta->gc,col(c),row(r-10),col(c),row(r+10));		
		default :
			gdk_draw_line(meta->draw,meta->gc,col(c+10),row(r-10),col(c-10),row(r+10));
			gdk_draw_line(meta->draw,meta->gc,col(c-10),row(r-10),col(c+10),row(r+10));
	}
}


static void gtk_meta_fill (void *p, double c[], int style, int n, int connect[])
/***** gfill
	fill an area given by n pairs of points (in c: x,y,x,y,...)
	with the style.
*****/
{
	GtkMeta *meta = (GtkMeta*)p;
	GtkWidget *widget = GTK_WIDGET(meta);

	int i,cc[64],ci[64],j,k,count;
	GdkPoint points[64];
	for (i=0; i<2*n; i+=2) ci[i]=(int)col(c[i]);
	for (i=1; i<2*n; i+=2) ci[i]=(int)row(c[i]);
	for (i=0; i<n; i++) {
		points[i].x=ci[2*i];
		points[i].y=ci[2*i+1];
	}

	setcolor(meta,(style==fill_filled)?fillcolor1:fillcolor2);
	gdk_draw_polygon(meta->draw,meta->gc,1,points,n);

	i=0;
	setline(meta,0,line_solid);
	setcolor(meta,1);
	while (i<n)
	{
		j=0;
		count=0;
		while (i<n && connect[i])
		{
			cc[j++]=ci[2*i];
			cc[j++]=ci[2*i+1];
			i++;
			count++;
		}
		if (i==n)
		{	
			cc[j++]=ci[0]; 
			cc[j++]=ci[1]; 
			count++;
		}
		else
		{	
			cc[j++]=ci[2*i]; 
			cc[j++]=ci[2*i+1]; 
			count++;
		}
		for (k=0; k<count-1; k++)
			gdk_draw_line(meta->draw,meta->gc,cc[2*k],cc[2*k+1],cc[2*k+2],cc[2*k+3]);
		while (i<n && !connect[i]) i++;
	}
}


static void gtk_meta_fillh (void *p, double c[], double hue, int color, int connect)
/***** gfillh
	fill an area given by 4 pairs of points (in c: x,y,x,y,...)
	with the hue and color. connect determines, if an outline is
	to be drawn.
*****/
{	
	GtkMeta *meta = (GtkMeta*)p;
	GtkWidget *widget = GTK_WIDGET(meta);

	int i,ci[8];
	GdkPoint points[5];
	for (i=0; i<8; i+=2) ci[i]=(int)col(c[i]);
	for (i=1; i<8; i+=2) ci[i]=(int)row(c[i]);
	for (i=0; i<4; i++) { 
		points[i].x=ci[2*i]; 
		points[i].y=ci[2*i+1]; 
	}
	points[4].x=points[0].x;
	points[4].y=points[0].y;
	sethue(meta,hue,color);
	gdk_draw_polygon(meta->draw,meta->stipplegc,1,points,4);

	if (!connect) return;
	setline(meta,0,line_solid);
	setcolor(meta,1);
	gdk_draw_lines(meta->draw,meta->gc,points,5);
}

static void gtk_meta_bar (void *p, double c, double r, double c1, double r1, double hue, int color, int connect)
{	
	GtkMeta *meta = (GtkMeta*)p;
	GtkWidget *widget = GTK_WIDGET(meta);

	int x,y,w,h;
	x=col(c); y=row(r);
	w=col(c1)-x; h=row(r1)-y;
	if (w<=0) w=1;
	if (h<=0) h=1;
	sethue(meta,hue,color);
	gdk_draw_rectangle(meta->draw,meta->stipplegc,1,x,y,w,h);
	if (!connect) return;
	setline(meta,0,line_solid);
	setcolor(meta,1);
	gdk_draw_rectangle(meta->draw,meta->gc,0,x,y,w,h);
}

static void gtk_meta_bar1 (void *p, double c, double r, double c1, double r1, int color, int connect)
{	
	GtkMeta *meta = (GtkMeta*)p;
	GtkWidget *widget = GTK_WIDGET(meta);

	int x,y,w,h;
	GdkGC *g;
	x=col(c); y=row(r);
	w=col(c1)-x; h=row(r1)-y;
	if (w<=0) w=1;
	if (h<=0) h=1;
	switch (connect)
	{	case bar_solid : setcolor(meta,color); g=meta->gc; break;
		case bar_frame : g=0; break;
		default : sethue(meta,0.5,color); g=meta->stipplegc; break;
	}
	if (g)
	{
		gdk_draw_rectangle(meta->draw,g,1,x,y,w,h);
	}
	if (connect==bar_solid) return;
	setline(meta,0,line_solid);
	setcolor(meta,1);
	gdk_draw_rectangle(meta->draw,meta->gc,0,x,y,w,h);
}

static void gtk_meta_text (void *p, double c, double r, char *text, int color, int alignment)
/***** gtext
	output a graphic text on screen.
*****/
{	
	GtkMeta *meta = (GtkMeta*)p;
	GtkWidget *widget = GTK_WIDGET(meta);

	int width;
	setcolor(meta,color);

	switch (alignment)
	{	
		case 0:
			gdk_draw_string(meta->draw,meta->font,meta->gc,col(c),row(r)+meta->font->ascent,text);
			break;

		case 1:
			width=gdk_string_width(meta->font,text);
			gdk_draw_string(meta->draw,meta->font,meta->gc,col(c)-width/2,row(r)+meta->font->ascent,text);
			break;
			
		case 2:
			width=gdk_string_width(meta->font,text);
			gdk_draw_string(meta->draw,meta->font,meta->gc,col(c)-width,row(r)+meta->font->ascent,text);
			break;	
	}
}

static void gdk_draw_rotated_string(GdkDrawable *drawable, GdkFont *font, GdkGC *gc, gint x, gint y, const gchar *text, gint angle, gint alignment);

static void gtk_meta_vtext (void *p, double c, double r, char *text, int color, int alignment)
/***** gtext
	output a graphic text on screen vertically.
*****/
{	
	GtkMeta *meta = (GtkMeta*)p;
	GtkWidget *widget = GTK_WIDGET(meta);

	setcolor(meta,color);
	gdk_draw_rotated_string(meta->draw,meta->font,meta->gc,col(c),row(r),text,-90,alignment);
}


static void gtk_meta_vutext (void *p, double c, double r, char *text, int color, int alignment)
/***** gtext
	output a graphic text on screen vertically.
*****/
{	
	GtkMeta *meta = (GtkMeta*)p;
	GtkWidget *widget = GTK_WIDGET(meta);

	setcolor(meta,color);
	gdk_draw_rotated_string(meta->draw,meta->font,meta->gc,col(c),row(r),text,90,alignment);
}

static void gtk_meta_scale (void *p, double s)
/***** scale
	scale the screen according s = true width / true height.
	This is not necessary on a window based system.
*****/
{
}


/****************************************************************************
 *	metagtk.c
 *
 *	utility function for vertical text drawing
 *
 ****************************************************************************/

/* gdk_draw_rotated_string
 *
 *	basic idea is from the GtkExtra plot widget.
 *	draw a string with angle of : 90, -90, 180°
 *	and alignment :	0 = left
 *					1 = center
 *					2 = right
 */
static void gdk_draw_rotated_string(GdkDrawable *drawable,
									GdkFont *font,
									GdkGC *gc,
									gint x, gint y,
									const gchar *text,
									gint angle,
									gint alignment)
{
	GdkBitmap *text_bitmap;
	GdkBitmap *text_mask;
	GdkImage *image;
	GdkGC *bitmap_gc;
	GdkColormap *colormap;
	GdkColor white, black, mask_color;
	gint xp = 0, yp = 0;
	gint width, height;
	gint old_width, old_height;
	gint i, j;
	gint tx, ty;
	
	if(!text || strlen(text) == 0) return;
	
	colormap = gdk_colormap_get_system();

	old_width = width = gdk_string_width(font,text);
	old_height = height = font->ascent + font->descent;

	if(angle == 90 || angle == -90 || angle == 270) {
		width = old_height;
		height = old_width;
	}
	
	/* initializing text bitmap - ajd */
	text_bitmap = gdk_pixmap_new(drawable, old_width, old_height, 1);
	bitmap_gc = gdk_gc_new(text_bitmap);
	gdk_color_white (colormap, &white);
	gdk_gc_set_foreground(bitmap_gc, &white);
	gdk_draw_rectangle(text_bitmap, bitmap_gc, TRUE, 0, 0, -1, -1);
	gdk_color_black (colormap, &black);
	gdk_gc_set_foreground(bitmap_gc, &black);
	gdk_draw_string (text_bitmap, font, bitmap_gc, 0, font->ascent, text);

	/* initializing clip mask bitmap - ajd */
	text_mask = gdk_pixmap_new(drawable, width, height, 1);
	mask_color = white;
	mask_color.pixel = 0;
	gdk_gc_set_foreground(bitmap_gc, &mask_color);
	gdk_draw_rectangle(text_mask, bitmap_gc, TRUE, 0, 0, -1, -1);
	mask_color = black;
	mask_color.pixel = 1;
	gdk_gc_set_foreground(bitmap_gc, &mask_color);

	/* performing text rotation and saving it onto clip mask bitmap - ajd */
	image = gdk_image_get(text_bitmap, 0, 0, old_width, old_height);
	for(j = 0; j < old_height; j++)
		for(i = 0; i < old_width; i++) {
			if( black.pixel == gdk_image_get_pixel(image, i, j) ){
				switch(angle){
					case 0:
						xp = i;
						yp = j;
						break;
					case 90:
						xp = j;
						yp = old_width - i;
						break;
					case 180:
					case -180:
						xp = old_width - i;
						yp = old_height - j;
						break;
					case 270:
					case -90:
						xp = old_height - j;
						yp = i;
						break;
				}
				gdk_draw_point(text_mask, bitmap_gc, xp, yp);
			}
		}
	
	gdk_image_destroy(image);

	switch (angle) {
		case 90:
			switch (alignment) {
				case 1:
					ty=y-height/2;
					break;
				case 2:
					ty=y;
					break;
				case 0:
				default:
					ty = y-height;
			}
			tx = x;
			break;
		case 270:
		case -90:
			switch (alignment) {
				case 1:
					ty=y-height/2;
					break;
				case 2:
					ty=y-height;
					break;
				case 0:
				default:
					ty = y;
			}
			tx=x-width;
			break;
		case 180:
		case -180:
			switch (alignment) {
				case 1:
					tx = x - width/2;
					break;
				case 2:
					tx= x;
					break;
				case 0:
				default:
					tx = x-width;
			}
			ty = y-height;
			break;
		case 0:
		default:
			switch (alignment) {
				case 1:
					tx = x - width/2;
					break;
				case 2:
					tx= x-width;
					break;
				case 0:
				default:
					tx = x;
			}
			ty = y;
	}

	gdk_gc_set_clip_mask (gc, text_mask);
	gdk_gc_set_clip_origin (gc, tx, ty);
	gdk_draw_rectangle(drawable, gc, TRUE, tx, ty, width, height);

	gdk_gc_set_clip_mask(gc, NULL);

	gdk_bitmap_unref(text_mask);
	gdk_gc_unref(bitmap_gc);
	gdk_pixmap_unref(text_bitmap);
}
