/* Dia -- an diagram creation/manipulation program * Copyright (C) 1998 Alexander Larsson * * diagdkrenderer.c - refactoring of the render to gdk facility * Copyright (C) 2002 Hans Breuer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #define PANGO_ENABLE_ENGINE #include #include #include "diagdkrenderer.h" #include "dia_image.h" #include "message.h" #include "color.h" #include "font.h" #include "text.h" #include "object.h" #include "textline.h" #include "time.h" #ifdef HAVE_FREETYPE #include #include #endif static int get_width_pixels (DiaRenderer *); static int get_height_pixels (DiaRenderer *); static void begin_render (DiaRenderer *); static void end_render (DiaRenderer *); static void set_linewidth (DiaRenderer *renderer, real linewidth); static void set_linecaps (DiaRenderer *renderer, LineCaps mode); static void set_linejoin (DiaRenderer *renderer, LineJoin mode); static void set_linestyle (DiaRenderer *renderer, LineStyle mode); static void set_dashlength (DiaRenderer *renderer, real length); static void set_fillstyle (DiaRenderer *renderer, FillStyle mode); static void draw_line (DiaRenderer *renderer, Point *start, Point *end, Color *color); static void fill_polygon (DiaRenderer *renderer, Point *points, int num_points, Color *color); static void draw_arc (DiaRenderer *renderer, Point *center, real width, real height, real angle1, real angle2, Color *color); static void fill_arc (DiaRenderer *renderer, Point *center, real width, real height, real angle1, real angle2, Color *color); static void draw_ellipse (DiaRenderer *renderer, Point *center, real width, real height, Color *color); static void fill_ellipse (DiaRenderer *renderer, Point *center, real width, real height, Color *color); static void draw_string (DiaRenderer *renderer, const gchar *text, Point *pos, Alignment alignment, Color *color); static void draw_text_line (DiaRenderer *renderer, TextLine *text, Point *pos, Color *color); static void draw_image (DiaRenderer *renderer, Point *point, real width, real height, DiaImage image); static void draw_rect (DiaRenderer *renderer, Point *ul_corner, Point *lr_corner, Color *color); static void fill_rect (DiaRenderer *renderer, Point *ul_corner, Point *lr_corner, Color *color); static void draw_fill_rect (DiaGdkRenderer *renderer, Point *ul_corner, Point *lr_corner, Color *color, gboolean fill); static void draw_polyline (DiaRenderer *renderer, Point *points, int num_points, Color *color); static void draw_polygon (DiaRenderer *renderer, Point *points, int num_points, Color *color); static void draw_object (DiaRenderer *renderer, DiaObject *object); static real get_text_width (DiaRenderer *renderer, const gchar *text, int length); static void dia_gdk_renderer_class_init (DiaGdkRendererClass *klass); static void renderer_init (DiaGdkRenderer *renderer, void*); static gpointer parent_class = NULL; /** Get the type object for the GdkRenderer. * @return A static GType object describing GdkRenderers. */ GType dia_gdk_renderer_get_type(void) { static GType object_type = 0; if (!object_type) { static const GTypeInfo object_info = { sizeof (DiaGdkRendererClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) dia_gdk_renderer_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (DiaGdkRenderer), 0, /* n_preallocs */ (GInstanceInitFunc)renderer_init /* init */ }; object_type = g_type_register_static (DIA_TYPE_RENDERER, "DiaGdkRenderer", &object_info, 0); } return object_type; } /** Initialize a renderer object. * @param renderer A renderer object to initialize. * @param p Ignored, purpose unknown. */ static void renderer_init(DiaGdkRenderer *renderer, void* p) { renderer->line_width = 1; renderer->line_style = GDK_LINE_SOLID; renderer->cap_style = GDK_CAP_BUTT; renderer->join_style = GDK_JOIN_ROUND; renderer->saved_line_style = LINESTYLE_SOLID; renderer->dash_length = 10; renderer->dot_length = 2; renderer->highlight_color = NULL; } /** Clean up a renderer object after use. * @param object Renderer object to free subobjects from. */ static void renderer_finalize(GObject *object) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); if (renderer->pixmap != NULL) gdk_pixmap_unref(renderer->pixmap); if (renderer->gc != NULL) gdk_gc_unref(renderer->gc); if (renderer->clip_region != NULL) gdk_region_destroy(renderer->clip_region); if (renderer->transform) g_object_unref (renderer->transform); G_OBJECT_CLASS (parent_class)->finalize (object); } /** Initialize members of the renderer class object. This sets up a bunch * of functions to call for various render functions. * @param klass The class object to initialize. */ static void dia_gdk_renderer_class_init(DiaGdkRendererClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); DiaRendererClass *renderer_class = DIA_RENDERER_CLASS (klass); parent_class = g_type_class_peek_parent (klass); object_class->finalize = renderer_finalize; renderer_class->get_width_pixels = get_width_pixels; renderer_class->get_height_pixels = get_height_pixels; renderer_class->begin_render = begin_render; renderer_class->end_render = end_render; renderer_class->set_linewidth = set_linewidth; renderer_class->set_linecaps = set_linecaps; renderer_class->set_linejoin = set_linejoin; renderer_class->set_linestyle = set_linestyle; renderer_class->set_dashlength = set_dashlength; renderer_class->set_fillstyle = set_fillstyle; renderer_class->draw_line = draw_line; renderer_class->fill_polygon = fill_polygon; renderer_class->draw_rect = draw_rect; renderer_class->fill_rect = fill_rect; renderer_class->draw_arc = draw_arc; renderer_class->fill_arc = fill_arc; renderer_class->draw_ellipse = draw_ellipse; renderer_class->fill_ellipse = fill_ellipse; /* use _bezier from DiaRenderer */ renderer_class->draw_string = draw_string; renderer_class->draw_text_line = draw_text_line; renderer_class->draw_image = draw_image; /* medium level functions */ renderer_class->draw_rect = draw_rect; renderer_class->draw_polyline = draw_polyline; renderer_class->draw_polygon = draw_polygon; renderer_class->draw_object = draw_object; /* Interactive functions */ renderer_class->get_text_width = get_text_width; } /** Convert Dia color objects into GDK color objects. * If the highlight color is set, that will be used instead. This allows * rendering of an object to do highlight rendering. * @param renderer The renderer to check for highlight color. * @param col A color object to convert. * @param gdk_col Resulting GDK convert. */ static void renderer_color_convert(DiaGdkRenderer *renderer, Color *col, GdkColor *gdk_col) { if (renderer->highlight_color != NULL) { color_convert(renderer->highlight_color, gdk_col); } else { color_convert(col, gdk_col); } } static void begin_render (DiaRenderer *object) { } static void end_render (DiaRenderer *object) { } static void set_linewidth (DiaRenderer *object, real linewidth) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); if (renderer->highlight_color != NULL) { /* 6 pixels wide -> 3 pixels beyond normal obj */ real border = dia_untransform_length(renderer->transform, 6); linewidth += border; } /* 0 == hairline **/ renderer->line_width = dia_transform_length(renderer->transform, linewidth); if (renderer->line_width<=0) renderer->line_width = 1; /* Minimum 1 pixel. */ gdk_gc_set_line_attributes(renderer->gc, renderer->line_width, renderer->line_style, renderer->cap_style, renderer->join_style); } static void set_linecaps (DiaRenderer *object, LineCaps mode) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); if (renderer->highlight_color != NULL) { renderer->cap_style = GDK_CAP_ROUND; } else { switch(mode) { case LINECAPS_BUTT: renderer->cap_style = GDK_CAP_BUTT; break; case LINECAPS_ROUND: renderer->cap_style = GDK_CAP_ROUND; break; case LINECAPS_PROJECTING: renderer->cap_style = GDK_CAP_PROJECTING; break; } } gdk_gc_set_line_attributes(renderer->gc, renderer->line_width, renderer->line_style, renderer->cap_style, renderer->join_style); } static void set_linejoin (DiaRenderer *object, LineJoin mode) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); if (renderer->highlight_color != NULL) { renderer->join_style = GDK_JOIN_ROUND; } else { switch(mode) { case LINEJOIN_MITER: renderer->join_style = GDK_JOIN_MITER; break; case LINEJOIN_ROUND: renderer->join_style = GDK_JOIN_ROUND; break; case LINEJOIN_BEVEL: renderer->join_style = GDK_JOIN_BEVEL; break; default : /* invalid mode, just here to set a breakpoint */ renderer->join_style = GDK_JOIN_ROUND; break; } } gdk_gc_set_line_attributes(renderer->gc, renderer->line_width, renderer->line_style, renderer->cap_style, renderer->join_style); } /** Set the dashes for this renderer. * offset determines where in the pattern the dashes will start. * It is used by the grid in particular to make the grid dashes line up. */ void dia_gdk_renderer_set_dashes(DiaGdkRenderer *renderer, int offset) { gint8 dash_list[6]; int hole_width; int pattern_length; switch(renderer->saved_line_style) { case LINESTYLE_SOLID: break; case LINESTYLE_DASHED: dash_list[0] = renderer->dash_length; dash_list[1] = renderer->dash_length; pattern_length = renderer->dash_length*2; gdk_gc_set_dashes(renderer->gc, offset, dash_list, 2); break; case LINESTYLE_DASH_DOT: hole_width = (renderer->dash_length - renderer->dot_length) / 2; if (hole_width==0) hole_width = 1; dash_list[0] = renderer->dash_length; dash_list[1] = hole_width; dash_list[2] = renderer->dot_length; dash_list[3] = hole_width; pattern_length = renderer->dash_length+renderer->dot_length+2*hole_width; gdk_gc_set_dashes(renderer->gc, offset, dash_list, 4); break; case LINESTYLE_DASH_DOT_DOT: hole_width = (renderer->dash_length - 2*renderer->dot_length) / 3; if (hole_width==0) hole_width = 1; dash_list[0] = renderer->dash_length; dash_list[1] = hole_width; dash_list[2] = renderer->dot_length; dash_list[3] = hole_width; dash_list[4] = renderer->dot_length; dash_list[5] = hole_width; pattern_length = renderer->dash_length+2*renderer->dot_length+3*hole_width; gdk_gc_set_dashes(renderer->gc, offset, dash_list, 6); break; case LINESTYLE_DOTTED: dash_list[0] = renderer->dot_length; dash_list[1] = renderer->dot_length; pattern_length = renderer->dot_length; gdk_gc_set_dashes(renderer->gc, offset, dash_list, 2); break; } } static void set_linestyle (DiaRenderer *object, LineStyle mode) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); renderer->saved_line_style = mode; switch(mode) { case LINESTYLE_SOLID: renderer->line_style = GDK_LINE_SOLID; break; case LINESTYLE_DASHED: renderer->line_style = GDK_LINE_ON_OFF_DASH; dia_gdk_renderer_set_dashes(renderer, 0); break; case LINESTYLE_DASH_DOT: renderer->line_style = GDK_LINE_ON_OFF_DASH; dia_gdk_renderer_set_dashes(renderer, 0); break; case LINESTYLE_DASH_DOT_DOT: renderer->line_style = GDK_LINE_ON_OFF_DASH; dia_gdk_renderer_set_dashes(renderer, 0); break; case LINESTYLE_DOTTED: renderer->line_style = GDK_LINE_ON_OFF_DASH; dia_gdk_renderer_set_dashes(renderer, 0); break; } gdk_gc_set_line_attributes(renderer->gc, renderer->line_width, renderer->line_style, renderer->cap_style, renderer->join_style); } static void set_dashlength (DiaRenderer *object, real length) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); /* dot = 10% of len */ real ddisp_len; ddisp_len = dia_transform_length(renderer->transform, length); renderer->dash_length = (int)floor(ddisp_len+0.5); renderer->dot_length = (int)floor(ddisp_len*0.1+0.5); if (renderer->dash_length<=0) renderer->dash_length = 1; if (renderer->dash_length>255) renderer->dash_length = 255; if (renderer->dot_length<=0) renderer->dot_length = 1; if (renderer->dot_length>255) renderer->dot_length = 255; set_linestyle(object, renderer->saved_line_style); } static void set_fillstyle (DiaRenderer *object, FillStyle mode) { switch(mode) { case FILLSTYLE_SOLID: break; default: message_error("gdk_renderer: Unsupported fill mode specified!\n"); } } static void draw_line (DiaRenderer *object, Point *start, Point *end, Color *line_color) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); GdkGC *gc = renderer->gc; GdkColor color; int x1,y1,x2,y2; dia_transform_coords(renderer->transform, start->x, start->y, &x1, &y1); dia_transform_coords(renderer->transform, end->x, end->y, &x2, &y2); renderer_color_convert(renderer, line_color, &color); gdk_gc_set_foreground(gc, &color); gdk_draw_line(renderer->pixmap, gc, x1, y1, x2, y2); } static void fill_polygon (DiaRenderer *object, Point *points, int num_points, Color *line_color) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); GdkGC *gc = renderer->gc; GdkColor color; GdkPoint *gdk_points; int i,x,y; gdk_points = g_new(GdkPoint, num_points); for (i=0;itransform, points[i].x, points[i].y, &x, &y); gdk_points[i].x = x; gdk_points[i].y = y; } renderer_color_convert(renderer, line_color, &color); gdk_gc_set_foreground(gc, &color); gdk_draw_polygon(renderer->pixmap, gc, TRUE, gdk_points, num_points); g_free(gdk_points); } static void draw_fill_arc (DiaRenderer *object, Point *center, real width, real height, real angle1, real angle2, Color *color, gboolean fill) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); GdkGC *gc = renderer->gc; GdkColor gdkcolor; gint top, left, bottom, right; real dangle; dia_transform_coords(renderer->transform, center->x - width/2, center->y - height/2, &left, &top); dia_transform_coords(renderer->transform, center->x + width/2, center->y + height/2, &right, &bottom); if ((left>right) || (top>bottom)) return; renderer_color_convert(renderer, color, &gdkcolor); gdk_gc_set_foreground(gc, &gdkcolor); dangle = angle2-angle1; if (dangle<0) dangle += 360.0; gdk_draw_arc(renderer->pixmap, gc, fill, left, top, right-left, bottom-top, (int) (angle1*64.0), (int) (dangle*64.0)); } static void draw_arc (DiaRenderer *object, Point *center, real width, real height, real angle1, real angle2, Color *color) { draw_fill_arc (object, center, width, height, angle1, angle2, color, FALSE); } static void fill_arc (DiaRenderer *object, Point *center, real width, real height, real angle1, real angle2, Color *color) { draw_fill_arc (object, center, width, height, angle1, angle2, color, TRUE); } static void draw_ellipse (DiaRenderer *object, Point *center, real width, real height, Color *color) { draw_arc(object, center, width, height, 0.0, 360.0, color); } static void fill_ellipse (DiaRenderer *object, Point *center, real width, real height, Color *color) { fill_arc(object, center, width, height, 0.0, 360.0, color); } /* Draw a highlighted version of a string. */ static void draw_highlighted_string(DiaGdkRenderer *renderer, PangoLayout *layout, int x, int y, GdkColor *color) { gint width, height; pango_layout_get_pixel_size(layout, &width, &height); gdk_gc_set_foreground(renderer->gc, color); gdk_draw_rectangle (renderer->pixmap, renderer->gc, TRUE, x-3, y-3, width+6, height+6); } static void draw_string (DiaRenderer *object, const gchar *text, Point *pos, Alignment alignment, Color *color) { TextLine *text_line = text_line_new(text, object->font, object->font_height); Point realigned_pos = *pos; realigned_pos.x -= text_line_get_alignment_adjustment(text_line, alignment); draw_text_line(object, text_line, &realigned_pos, color); } #ifdef HAVE_FREETYPE static void initialize_ft_bitmap(FT_Bitmap *ftbitmap, int width, int height) { int rowstride = 32*((width+31)/31); guint8 *graybitmap = (guint8*)g_new0(guint8, height*rowstride); ftbitmap->rows = height; ftbitmap->width = width; ftbitmap->pitch = rowstride; ftbitmap->buffer = graybitmap; ftbitmap->num_grays = 256; ftbitmap->pixel_mode = ft_pixel_mode_grays; ftbitmap->palette_mode = 0; ftbitmap->palette = 0; } typedef struct _FreetypeCacheData { int x; int y; int width; int height; GdkPixbuf *rgba; } FreetypeCacheData; static void free_freetype_cache_data(gpointer data) { FreetypeCacheData *ftdata = (FreetypeCacheData*) data; g_object_unref(ftdata->rgba); g_free(ftdata); } #endif /** Draw a TextLine object. * @param object The renderer object to use for transform and output * @param text_line The TextLine to render, including font and height. * @param pos The position to render it at. * @param color The color to render it with. */ static void draw_text_line (DiaRenderer *object, TextLine *text_line, Point *pos, Color *color) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); GdkColor gdkcolor; int x,y; Point start_pos; PangoLayout* layout = NULL; const gchar *text = text_line_get_string(text_line); int height_pixels; real font_height = text_line_get_height(text_line); real scale = dia_transform_length(renderer->transform, 1.0); if (text == NULL || *text == '\0') return; /* Don't render empty strings. */ point_copy(&start_pos,pos); renderer_color_convert(renderer, color, &gdkcolor); height_pixels = dia_transform_length(renderer->transform, font_height); if (height_pixels < 2) { /* "Greeking" instead of making tiny font */ int width_pixels = dia_transform_length(renderer->transform, text_line_get_width(text_line)); gdk_gc_set_foreground(renderer->gc, &gdkcolor); gdk_gc_set_dashes(renderer->gc, 0, "\1\2", 2); dia_transform_coords(renderer->transform, start_pos.x, start_pos.y, &x, &y); gdk_draw_line(renderer->pixmap, renderer->gc, x, y, x + width_pixels, y); return; } else { real adjust = 0.0; adjust = text_line_get_ascent(text_line); start_pos.y -= adjust; dia_transform_coords(renderer->transform, start_pos.x, start_pos.y, &x, &y); layout = dia_font_build_layout(text, text_line->font, dia_transform_length(renderer->transform, text_line->height)/20.0); text_line_adjust_layout_line(text_line, pango_layout_get_line(layout, 0), scale/20.0); if (renderer->highlight_color != NULL) { draw_highlighted_string(renderer, layout, x, y, &gdkcolor); } else { #if defined HAVE_FREETYPE { FT_Bitmap ftbitmap; int width, height; GdkPixbuf *rgba = NULL; width = dia_transform_length(renderer->transform, text_line_get_width(text_line)); height = dia_transform_length(renderer->transform, text_line_get_height(text_line)); if (width > 0) { int stride; guchar* pixels; int i,j; guint8 *graybitmap; FreetypeCacheData *cache; initialize_ft_bitmap(&ftbitmap, width, height); pango_ft2_render_layout(&ftbitmap, layout, 0, 0); graybitmap = ftbitmap.buffer; rgba = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height); stride = gdk_pixbuf_get_rowstride(rgba); pixels = gdk_pixbuf_get_pixels(rgba); for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { pixels[i*stride+j*4] = gdkcolor.red>>8; pixels[i*stride+j*4+1] = gdkcolor.green>>8; pixels[i*stride+j*4+2] = gdkcolor.blue>>8; pixels[i*stride+j*4+3] = graybitmap[i*ftbitmap.pitch+j]; } } g_free(graybitmap); gdk_draw_pixbuf(renderer->pixmap, renderer->gc, rgba, 0, 0, x, y, width, height, GDK_RGB_DITHER_NONE, 0, 0); g_object_unref(G_OBJECT(rgba)); } } #else gdk_gc_set_foreground(renderer->gc, &gdkcolor); gdk_draw_layout(renderer->pixmap, renderer->gc, x, y, layout); #endif g_object_unref(G_OBJECT(layout)); } } } /* Get the width of the given text in cm */ static real get_text_width(DiaRenderer *object, const gchar *text, int length) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); real result; TextLine *text_line; if (length != g_utf8_strlen(text, -1)) { char *othertx; int ulen; /* A couple UTF8-chars: æblegrød Š Ť Ž ę ć ń уфхцНОПРЄ є Ґ Њ Ћ Џ */ ulen = g_utf8_offset_to_pointer(text, length)-text; if (!g_utf8_validate(text, ulen, NULL)) { g_warning ("Text at char %d not valid\n", length); } othertx = g_strndup(text, ulen); text_line = text_line_new(othertx, object->font, object->font_height); } else { text_line = text_line_new(text, object->font, object->font_height); } result = text_line_get_width(text_line); text_line_destroy(text_line); return result; } static void draw_image (DiaRenderer *object, Point *point, real width, real height, DiaImage image) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); if (renderer->highlight_color != NULL) { Point lr; DiaRendererClass *self_class = DIA_RENDERER_GET_CLASS (object); lr = *point; lr.x += width; lr.y += height; self_class->fill_rect(object, point, &lr, renderer->highlight_color); } else { int real_width, real_height, real_x, real_y; real_width = dia_transform_length(renderer->transform, width); real_height = dia_transform_length(renderer->transform, height); dia_transform_coords(renderer->transform, point->x, point->y, &real_x, &real_y); dia_image_draw(image, renderer->pixmap, renderer->gc, real_x, real_y, real_width, real_height); } } /* * medium level functions */ static void draw_fill_rect (DiaGdkRenderer *renderer, Point *ul_corner, Point *lr_corner, Color *color, gboolean fill) { GdkGC *gc = renderer->gc; GdkColor gdkcolor; gint top, bottom, left, right; dia_transform_coords(renderer->transform, ul_corner->x, ul_corner->y, &left, &top); dia_transform_coords(renderer->transform, lr_corner->x, lr_corner->y, &right, &bottom); if ((left>right) || (top>bottom)) return; renderer_color_convert(renderer, color, &gdkcolor); gdk_gc_set_foreground(gc, &gdkcolor); gdk_draw_rectangle (renderer->pixmap, gc, fill, left, top, right-left, bottom-top); } static void draw_rect (DiaRenderer *object, Point *ul_corner, Point *lr_corner, Color *color) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); draw_fill_rect (renderer, ul_corner, lr_corner, color, FALSE); } static void fill_rect (DiaRenderer *object, Point *ul_corner, Point *lr_corner, Color *color) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); draw_fill_rect (renderer, ul_corner, lr_corner, color, TRUE); } static void draw_polyline (DiaRenderer *self, Point *points, int num_points, Color *line_color) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (self); GdkGC *gc = renderer->gc; GdkColor color; GdkPoint *gdk_points; int i,x,y; gdk_points = g_new(GdkPoint, num_points); for (i=0;itransform, points[i].x, points[i].y, &x, &y); gdk_points[i].x = x; gdk_points[i].y = y; } renderer_color_convert(renderer, line_color, &color); gdk_gc_set_foreground(gc, &color); gdk_draw_lines(renderer->pixmap, gc, gdk_points, num_points); g_free(gdk_points); } static void draw_polygon (DiaRenderer *self, Point *points, int num_points, Color *line_color) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (self); GdkGC *gc = renderer->gc; GdkColor color; GdkPoint *gdk_points; int i,x,y; gdk_points = g_new(GdkPoint, num_points); for (i=0;itransform, points[i].x, points[i].y, &x, &y); gdk_points[i].x = x; gdk_points[i].y = y; } renderer_color_convert(renderer, line_color, &color); gdk_gc_set_foreground(gc, &color); gdk_draw_polygon(renderer->pixmap, gc, FALSE, gdk_points, num_points); g_free(gdk_points); } static void draw_object (DiaRenderer *renderer, DiaObject *object) { if (renderer->is_interactive && object->highlight_color != NULL) { DiaGdkRenderer *gdk_rend = DIA_GDK_RENDERER(renderer); gdk_rend->highlight_color = object->highlight_color; object->ops->draw(object, renderer); gdk_rend->highlight_color = NULL; } object->ops->draw(object, renderer); } static int get_width_pixels (DiaRenderer *object) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); int width = 0; if (renderer->pixmap) gdk_drawable_get_size (GDK_DRAWABLE (renderer->pixmap), &width, NULL); return width; } static int get_height_pixels (DiaRenderer *object) { DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object); int height = 0; if (renderer->pixmap) gdk_drawable_get_size (GDK_DRAWABLE (renderer->pixmap), NULL, &height); return height; }