/**************************************************************************** * metagtk.c * * gtk graphic device : widget for graphic output * ****************************************************************************/ #include #include #include #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;icmap,&(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;icolors[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; idraw,meta->gc,1,points,n); i=0; setline(meta,0,line_solid); setcolor(meta,1); while (idraw,meta->gc,cc[2*k],cc[2*k+1],cc[2*k+2],cc[2*k+3]); while (idraw,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); }