Easier adjusting of layouts
[dia.git] / lib / diarenderer.c
blobaf2a365e6b33abf3f2a93779c204e82ef90aa725
1 /* Dia -- an diagram creation/manipulation program
2 * Copyright (C) 1998 Alexander Larsson
4 * diarenderer.c - GObject based dia renderer base class
5 * Copyright (C) 1998-2002 Various Dia developers
6 * Copyright (C) 2002 Hans Breuer (refactoring)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include "diarenderer.h"
25 #include "object.h"
26 #include "text.h"
27 #include "textline.h"
29 struct _BezierApprox {
30 Point *points;
31 int numpoints;
32 int currpoint;
35 static void dia_renderer_class_init (DiaRendererClass *klass);
37 static int get_width_pixels (DiaRenderer *);
38 static int get_height_pixels (DiaRenderer *);
40 static void begin_render (DiaRenderer *);
41 static void end_render (DiaRenderer *);
43 static void set_linewidth (DiaRenderer *renderer, real linewidth);
44 static void set_linecaps (DiaRenderer *renderer, LineCaps mode);
45 static void set_linejoin (DiaRenderer *renderer, LineJoin mode);
46 static void set_linestyle (DiaRenderer *renderer, LineStyle mode);
47 static void set_dashlength (DiaRenderer *renderer, real length);
48 static void set_fillstyle (DiaRenderer *renderer, FillStyle mode);
49 static void set_font (DiaRenderer *renderer, DiaFont *font, real height);
51 static void draw_line (DiaRenderer *renderer,
52 Point *start, Point *end,
53 Color *color);
54 static void fill_rect (DiaRenderer *renderer,
55 Point *ul_corner, Point *lr_corner,
56 Color *color);
57 static void fill_polygon (DiaRenderer *renderer,
58 Point *points, int num_points,
59 Color *color);
60 static void draw_arc (DiaRenderer *renderer,
61 Point *center,
62 real width, real height,
63 real angle1, real angle2,
64 Color *color);
65 static void fill_arc (DiaRenderer *renderer,
66 Point *center,
67 real width, real height,
68 real angle1, real angle2,
69 Color *color);
70 static void draw_ellipse (DiaRenderer *renderer,
71 Point *center,
72 real width, real height,
73 Color *color);
74 static void fill_ellipse (DiaRenderer *renderer,
75 Point *center,
76 real width, real height,
77 Color *color);
78 static void draw_bezier (DiaRenderer *renderer,
79 BezPoint *points,
80 int numpoints,
81 Color *color);
82 static void fill_bezier (DiaRenderer *renderer,
83 BezPoint *points,
84 int numpoints,
85 Color *color);
86 static void draw_string (DiaRenderer *renderer,
87 const gchar *text,
88 Point *pos,
89 Alignment alignment,
90 Color *color);
91 static void draw_image (DiaRenderer *renderer,
92 Point *point,
93 real width, real height,
94 DiaImage image);
95 static void draw_text (DiaRenderer *renderer,
96 Text *text);
97 static void draw_text_line (DiaRenderer *renderer,
98 TextLine *text_line, Point *pos, Color *color);
100 static void draw_rect (DiaRenderer *renderer,
101 Point *ul_corner, Point *lr_corner,
102 Color *color);
103 static void draw_polyline (DiaRenderer *renderer,
104 Point *points, int num_points,
105 Color *color);
106 static void draw_rounded_polyline (DiaRenderer *renderer,
107 Point *points, int num_points,
108 Color *color, real radius);
109 static void draw_polygon (DiaRenderer *renderer,
110 Point *points, int num_points,
111 Color *color);
113 static real get_text_width (DiaRenderer *renderer,
114 const gchar *text, int length);
116 static void draw_rounded_rect (DiaRenderer *renderer,
117 Point *ul_corner, Point *lr_corner,
118 Color *color, real radius);
119 static void fill_rounded_rect (DiaRenderer *renderer,
120 Point *ul_corner, Point *lr_corner,
121 Color *color, real radius);
122 static void draw_line_with_arrows (DiaRenderer *renderer,
123 Point *start, Point *end,
124 real line_width,
125 Color *line_color,
126 Arrow *start_arrow,
127 Arrow *end_arrow);
128 static void draw_arc_with_arrows (DiaRenderer *renderer,
129 Point *start, Point *end,
130 Point *midpoint,
131 real line_width,
132 Color *color,
133 Arrow *start_arrow,
134 Arrow *end_arrow);
135 static void draw_polyline_with_arrows (DiaRenderer *renderer,
136 Point *points, int num_points,
137 real line_width,
138 Color *color,
139 Arrow *start_arrow,
140 Arrow *end_arrow);
141 static void draw_rounded_polyline_with_arrows (DiaRenderer *renderer,
142 Point *points, int num_points,
143 real line_width,
144 Color *color,
145 Arrow *start_arrow,
146 Arrow *end_arrow,
147 real radius);
149 static void draw_bezier_with_arrows (DiaRenderer *renderer,
150 BezPoint *points,
151 int num_points,
152 real line_width,
153 Color *color,
154 Arrow *start_arrow,
155 Arrow *end_arrow);
157 static gpointer parent_class = NULL;
159 GType
160 dia_renderer_get_type (void)
162 static GType object_type = 0;
164 if (!object_type)
166 static const GTypeInfo object_info =
168 sizeof (DiaRendererClass),
169 (GBaseInitFunc) NULL,
170 (GBaseFinalizeFunc) NULL,
171 (GClassInitFunc) dia_renderer_class_init,
172 NULL, /* class_finalize */
173 NULL, /* class_data */
174 sizeof (DiaRenderer),
175 0, /* n_preallocs */
176 NULL /* init */
179 object_type = g_type_register_static (G_TYPE_OBJECT,
180 "DiaRenderer",
181 &object_info, 0);
184 return object_type;
187 static void
188 draw_object (DiaRenderer *renderer,
189 DiaObject *object)
191 object->ops->draw(object, renderer);
194 static void
195 renderer_finalize (GObject *object)
197 DiaRenderer *renderer = DIA_RENDERER (object);
199 if (renderer->font)
200 dia_font_unref (renderer->font);
202 if (renderer->bezier)
204 if (renderer->bezier->points)
205 g_free (renderer->bezier->points);
206 g_free (renderer->bezier);
209 G_OBJECT_CLASS (parent_class)->finalize (object);
212 static void
213 dia_renderer_class_init (DiaRendererClass *klass)
215 GObjectClass *object_class = G_OBJECT_CLASS (klass);
216 DiaRendererClass *renderer_class = DIA_RENDERER_CLASS (klass);
218 parent_class = g_type_class_peek_parent (klass);
220 object_class->finalize = renderer_finalize;
222 renderer_class->get_width_pixels = get_width_pixels;
223 renderer_class->get_height_pixels = get_height_pixels;
224 renderer_class->draw_object = draw_object;
225 renderer_class->get_text_width = get_text_width;
227 renderer_class->begin_render = begin_render;
228 renderer_class->end_render = end_render;
230 renderer_class->set_linewidth = set_linewidth;
231 renderer_class->set_linecaps = set_linecaps;
232 renderer_class->set_linejoin = set_linejoin;
233 renderer_class->set_linestyle = set_linestyle;
234 renderer_class->set_dashlength = set_dashlength;
235 renderer_class->set_fillstyle = set_fillstyle;
236 renderer_class->set_font = set_font;
238 renderer_class->draw_line = draw_line;
239 renderer_class->fill_rect = fill_rect;
240 renderer_class->fill_polygon = fill_polygon;
241 renderer_class->draw_arc = draw_arc;
242 renderer_class->fill_arc = fill_arc;
243 renderer_class->draw_ellipse = draw_ellipse;
244 renderer_class->fill_ellipse = fill_ellipse;
245 renderer_class->draw_string = draw_string;
246 renderer_class->draw_image = draw_image;
248 /* medium level functions */
249 renderer_class->draw_bezier = draw_bezier;
250 renderer_class->fill_bezier = fill_bezier;
251 renderer_class->draw_rect = draw_rect;
252 renderer_class->draw_rounded_polyline = draw_rounded_polyline;
253 renderer_class->draw_polyline = draw_polyline;
254 renderer_class->draw_polygon = draw_polygon;
255 renderer_class->draw_text = draw_text;
256 renderer_class->draw_text_line = draw_text_line;
258 /* highest level functions */
259 renderer_class->draw_rounded_rect = draw_rounded_rect;
260 renderer_class->fill_rounded_rect = fill_rounded_rect;
261 renderer_class->draw_line_with_arrows = draw_line_with_arrows;
262 renderer_class->draw_arc_with_arrows = draw_arc_with_arrows;
263 renderer_class->draw_polyline_with_arrows = draw_polyline_with_arrows;
264 renderer_class->draw_rounded_polyline_with_arrows = draw_rounded_polyline_with_arrows;
265 renderer_class->draw_bezier_with_arrows = draw_bezier_with_arrows;
268 static void
269 begin_render (DiaRenderer *object)
271 g_warning ("%s::begin_render not implemented!",
272 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object)));
275 static void
276 end_render (DiaRenderer *object)
278 g_warning ("%s::end_render not implemented!",
279 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object)));
282 static void
283 set_linewidth (DiaRenderer *object, real linewidth)
285 g_warning ("%s::set_line_width not implemented!",
286 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object)));
289 static void
290 set_linecaps (DiaRenderer *object, LineCaps mode)
292 g_warning ("%s::set_line_caps not implemented!",
293 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (object)));
296 static void
297 set_linejoin (DiaRenderer *renderer, LineJoin mode)
299 g_warning ("%s::set_line_join not implemented!",
300 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
303 static void
304 set_linestyle (DiaRenderer *renderer, LineStyle mode)
306 g_warning ("%s::set_line_style not implemented!",
307 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
310 static void
311 set_dashlength (DiaRenderer *renderer, real length)
313 g_warning ("%s::set_dash_length not implemented!",
314 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
317 static void
318 set_fillstyle (DiaRenderer *renderer, FillStyle mode)
320 g_warning ("%s::set_fill_style not implemented!",
321 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
324 static void
325 set_font (DiaRenderer *renderer, DiaFont *font, real height)
327 /* if it's the same font we must ref it first */
328 dia_font_ref (font);
329 if (renderer->font)
330 dia_font_unref (renderer->font);
331 renderer->font = font;
332 renderer->font_height = height;
336 static void
337 draw_line (DiaRenderer *renderer, Point *start, Point *end, Color *color)
339 g_warning ("%s::draw_line not implemented!",
340 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
343 static void
344 fill_polygon (DiaRenderer *renderer, Point *points, int num_points, Color *color)
346 g_warning ("%s::fill_polygon not implemented!",
347 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
350 static void
351 draw_arc (DiaRenderer *renderer, Point *center,
352 real width, real height, real angle1, real angle2,
353 Color *color)
355 g_warning ("%s::draw_arc not implemented!",
356 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
359 static void
360 fill_rect (DiaRenderer *renderer,
361 Point *ul_corner, Point *lr_corner,
362 Color *color)
364 g_warning ("%s::fill_rect not implemented!",
365 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
368 static void
369 fill_arc (DiaRenderer *renderer, Point *center,
370 real width, real height, real angle1, real angle2,
371 Color *color)
373 g_warning ("%s::fill_arc not implemented!",
374 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
377 static void
378 draw_ellipse (DiaRenderer *renderer, Point *center,
379 real width, real height,
380 Color *color)
382 g_warning ("%s::draw_ellipse not implemented!",
383 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
386 static void
387 fill_ellipse (DiaRenderer *renderer, Point *center,
388 real width, real height, Color *color)
390 g_warning ("%s::fill_ellipse not implemented!",
391 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
394 static void
395 draw_string (DiaRenderer *renderer,
396 const gchar *text, Point *pos, Alignment alignment,
397 Color *color)
399 g_warning ("%s::draw_string not implemented!",
400 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
403 /** Default implementation of draw_text */
404 static void draw_text(DiaRenderer *renderer,
405 Text *text) {
406 Point pos;
407 int i;
409 DIA_RENDERER_GET_CLASS(renderer)->set_font(renderer, text->font, text->height);
411 pos = text->position;
413 for (i=0;i<text->numlines;i++) {
414 DIA_RENDERER_GET_CLASS(renderer)->draw_string(renderer,
415 text->line[i],
416 &pos, text->alignment,
417 &text->color);
418 pos.y += text->height;
422 /** Default implementation of draw_text_line */
423 static void draw_text_line(DiaRenderer *renderer,
424 TextLine *text_line, Point *pos, Color *color) {
425 DIA_RENDERER_GET_CLASS(renderer)->set_font(renderer,
426 text_line_get_font(text_line),
427 text_line_get_height(text_line));
429 DIA_RENDERER_GET_CLASS(renderer)->draw_string(renderer,
430 text_line_get_string(text_line),
431 pos, ALIGN_LEFT,
432 color);
435 static void
436 draw_image (DiaRenderer *renderer,
437 Point *point, real width, real height,
438 DiaImage image)
440 g_warning ("%s::draw_image not implemented!",
441 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
446 * medium level functions, implemented by the above
448 /* Bezier implementation notes:
449 * These beziers have the following basis matrix:
450 * [-1 3 -3 1]
451 * [ 3 -6 3 0]
452 * [-3 3 0 0]
453 * [ 1 0 0 0]
454 * (At least that's what Hearn and Baker says for beziers.)
456 #define BEZIER_SUBDIVIDE_LIMIT 0.01
457 #define BEZIER_SUBDIVIDE_LIMIT_SQ (BEZIER_SUBDIVIDE_LIMIT*BEZIER_SUBDIVIDE_LIMIT)
459 static void
460 bezier_add_point(BezierApprox *bezier,
461 Point *point)
463 /* Grow if needed: */
464 if (bezier->currpoint == bezier->numpoints) {
465 bezier->numpoints += 40;
466 bezier->points = g_realloc(bezier->points,
467 bezier->numpoints*sizeof(Point));
470 bezier->points[bezier->currpoint] = *point;
472 bezier->currpoint++;
475 static void
476 bezier_add_lines(BezierApprox *bezier,
477 Point points[4])
479 Point u, v, x, y;
480 Point r[4];
481 Point s[4];
482 Point middle;
483 coord delta;
484 real v_len_sq;
486 /* Check if almost flat: */
487 u = points[1];
488 point_sub(&u, &points[0]);
489 v = points[3];
490 point_sub(&v, &points[0]);
491 y = v;
492 v_len_sq = point_dot(&v,&v);
493 if (isnan(v_len_sq)) {
494 g_warning("v_len_sq is NaN while calculating bezier curve!");
495 return;
497 if (v_len_sq < 0.000001)
498 v_len_sq = 0.000001;
499 point_scale(&y, point_dot(&u,&v)/v_len_sq);
500 x = u;
501 point_sub(&x,&y);
502 delta = point_dot(&x,&x);
503 if (delta < BEZIER_SUBDIVIDE_LIMIT_SQ) {
504 u = points[2];
505 point_sub(&u, &points[3]);
506 v = points[0];
507 point_sub(&v, &points[3]);
508 y = v;
509 v_len_sq = point_dot(&v,&v);
510 if (v_len_sq < 0.000001)
511 v_len_sq = 0.000001;
512 point_scale(&y, point_dot(&u,&v)/v_len_sq);
513 x = u;
514 point_sub(&x,&y);
515 delta = point_dot(&x,&x);
516 if (delta < BEZIER_SUBDIVIDE_LIMIT_SQ) { /* Almost flat, draw a line */
517 bezier_add_point(bezier, &points[3]);
518 return;
521 /* Subdivide into two bezier curves: */
523 middle = points[1];
524 point_add(&middle, &points[2]);
525 point_scale(&middle, 0.5);
527 r[0] = points[0];
529 r[1] = points[0];
530 point_add(&r[1], &points[1]);
531 point_scale(&r[1], 0.5);
533 r[2] = r[1];
534 point_add(&r[2], &middle);
535 point_scale(&r[2], 0.5);
537 s[3] = points[3];
539 s[2] = points[2];
540 point_add(&s[2], &points[3]);
541 point_scale(&s[2], 0.5);
543 s[1] = s[2];
544 point_add(&s[1], &middle);
545 point_scale(&s[1], 0.5);
547 r[3] = r[2];
548 point_add(&r[3], &s[1]);
549 point_scale(&r[3], 0.5);
551 s[0] = r[3];
553 bezier_add_lines(bezier, r);
554 bezier_add_lines(bezier, s);
557 static void
558 bezier_add_curve(BezierApprox *bezier,
559 Point points[4])
561 /* Is the bezier curve malformed? */
562 if ( (distance_point_point(&points[0], &points[1]) < 0.00001) &&
563 (distance_point_point(&points[2], &points[3]) < 0.00001) &&
564 (distance_point_point(&points[0], &points[3]) < 0.00001)) {
565 bezier_add_point(bezier, &points[3]);
568 bezier_add_lines(bezier, points);
571 static void
572 approximate_bezier (BezierApprox *bezier,
573 BezPoint *points, int numpoints)
575 Point curve[4];
576 int i;
578 if (points[0].type != BEZ_MOVE_TO)
579 g_warning("first BezPoint must be a BEZ_MOVE_TO");
580 curve[3] = points[0].p1;
581 bezier_add_point(bezier, &points[0].p1);
582 for (i = 1; i < numpoints; i++)
583 switch (points[i].type) {
584 case BEZ_MOVE_TO:
585 g_warning("only first BezPoint can be a BEZ_MOVE_TO");
586 curve[3] = points[i].p1;
587 break;
588 case BEZ_LINE_TO:
589 bezier_add_point(bezier, &points[i].p1);
590 curve[3] = points[i].p1;
591 break;
592 case BEZ_CURVE_TO:
593 curve[0] = curve[3];
594 curve[1] = points[i].p1;
595 curve[2] = points[i].p2;
596 curve[3] = points[i].p3;
597 bezier_add_curve(bezier, curve);
598 break;
602 /* bezier approximation with straight lines */
603 static void
604 draw_bezier (DiaRenderer *renderer,
605 BezPoint *points, int numpoints,
606 Color *color)
608 BezierApprox *bezier;
610 if (renderer->bezier)
611 bezier = renderer->bezier;
612 else
613 renderer->bezier = bezier = g_new0 (BezierApprox, 1);
615 if (bezier->points == NULL) {
616 bezier->numpoints = 30;
617 bezier->points = g_malloc(bezier->numpoints*sizeof(Point));
620 bezier->currpoint = 0;
621 approximate_bezier (bezier, points, numpoints);
623 DIA_RENDERER_GET_CLASS (renderer)->draw_polyline (renderer,
624 bezier->points,
625 bezier->currpoint,
626 color);
629 static void
630 fill_bezier (DiaRenderer *renderer,
631 BezPoint *points, int numpoints,
632 Color *color)
634 BezierApprox *bezier;
636 if (renderer->bezier)
637 bezier = renderer->bezier;
638 else
639 renderer->bezier = bezier = g_new0 (BezierApprox, 1);
641 if (bezier->points == NULL) {
642 bezier->numpoints = 30;
643 bezier->points = g_malloc(bezier->numpoints*sizeof(Point));
646 bezier->currpoint = 0;
647 approximate_bezier (bezier, points, numpoints);
649 DIA_RENDERER_GET_CLASS (renderer)->fill_polygon (renderer,
650 bezier->points,
651 bezier->currpoint,
652 color);
655 static void
656 draw_rect (DiaRenderer *renderer,
657 Point *ul_corner, Point *lr_corner,
658 Color *color)
660 DiaRendererClass *klass = DIA_RENDERER_GET_CLASS (renderer);
661 Point ur, ll;
663 ur.x = lr_corner->x;
664 ur.y = ul_corner->y;
665 ll.x = ul_corner->x;
666 ll.y = lr_corner->y;
668 klass->draw_line (renderer, ul_corner, &ur, color);
669 klass->draw_line (renderer, &ur, lr_corner, color);
670 klass->draw_line (renderer, lr_corner, &ll, color);
671 klass->draw_line (renderer, &ll, ul_corner, color);
674 static void
675 draw_polyline (DiaRenderer *renderer,
676 Point *points, int num_points,
677 Color *color)
679 DiaRendererClass *klass = DIA_RENDERER_GET_CLASS (renderer);
680 int i;
682 for (i = 0; i < num_points - 1; i++)
683 klass->draw_line (renderer, &points[i+0], &points[i+1], color);
687 /* calculate the maximum possible radius for 3 points
688 use the following,
689 given points p1,p2, and p3
690 let c = min(length(p1,p2)/2,length(p2,p3)/2)
691 let a = dot2(p1-p2, p3-p2)
692 (ie, angle between lines p1,p2 and p2,p3)
693 then maxr = c * sin(a/2)
695 static real
696 calculate_min_radius( Point *p1, Point *p2, Point *p3 )
698 real c;
699 real a;
700 Point v1,v2;
702 c = MIN(distance_point_point(p1,p2)/2,distance_point_point(p2,p3)/2);
703 v1.x = p1->x-p2->x; v1.y = p1->y-p2->y;
704 v2.x = p3->x-p2->x; v2.y = p3->y-p2->y;
705 a = dot2(&v1,&v2);
706 return (c*sin(a/2));
709 /** Draw a polyline with optionally rounded corners.
710 * Based on draw_line and draw_arc, but uses draw_polyline when
711 * the rounding is too small.
713 static void
714 draw_rounded_polyline (DiaRenderer *renderer,
715 Point *points, int num_points,
716 Color *color, real radius)
718 DiaRendererClass *klass = DIA_RENDERER_GET_CLASS (renderer);
719 int i = 0;
720 Point p1,p2,p3,p4 ;
721 Point *p;
722 p = points;
724 if (radius < 0.00001) {
725 klass->draw_polyline(renderer, points, num_points, color);
726 return;
729 /* skip arc computations if we only have points */
730 if ( num_points <= 2 ) {
731 i = 0;
732 p1.x = p[i].x; p1.y = p[i].y;
733 p2.x = p[i+1].x; p2.y = p[i+1].y;
734 klass->draw_line(renderer,&p1,&p2,color);
735 return;
738 i = 0;
739 /* full rendering 3 or more points */
740 p1.x = p[i].x; p1.y = p[i].y;
741 p2.x = p[i+1].x; p2.y = p[i+1].y;
742 for (i = 0; i <= num_points - 3; i++) {
743 Point c;
744 real start_angle, stop_angle;
745 real min_radius;
746 p3.x = p[i+1].x; p3.y = p[i+1].y;
747 p4.x = p[i+2].x; p4.y = p[i+2].y;
749 /* adjust the radius if it would cause odd rendering */
750 min_radius = MIN(radius, calculate_min_radius(&p1,&p2,&p4));
751 fillet(&p1,&p2,&p3,&p4, min_radius, &c, &start_angle, &stop_angle);
752 klass->draw_arc(renderer, &c, min_radius*2, min_radius*2,
753 start_angle,
754 stop_angle, color);
755 klass->draw_line(renderer, &p1, &p2, color);
756 p1.x = p3.x; p1.y = p3.y;
757 p2.x = p4.x; p2.y = p4.y;
759 klass->draw_line(renderer, &p3, &p4, color);
762 static void
763 draw_polygon (DiaRenderer *renderer,
764 Point *points, int num_points,
765 Color *color)
767 DiaRendererClass *klass = DIA_RENDERER_GET_CLASS (renderer);
768 int i;
770 g_return_if_fail (num_points > 1);
772 for (i = 0; i < num_points - 1; i++)
773 klass->draw_line (renderer, &points[i+0], &points[i+1], color);
774 /* close it in any case */
775 if ( (points[0].x != points[num_points-1].x)
776 || (points[0].y != points[num_points-1].y))
777 klass->draw_line (renderer, &points[num_points-1], &points[0], color);
780 static void
781 draw_rounded_rect (DiaRenderer *renderer,
782 Point *ul_corner, Point *lr_corner,
783 Color *color, real radius)
785 DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
786 Point start, end, center;
788 radius = MIN(radius, (lr_corner->x-ul_corner->x)/2);
789 radius = MIN(radius, (lr_corner->y-ul_corner->y)/2);
790 start.x = center.x = ul_corner->x+radius;
791 end.x = lr_corner->x-radius;
792 start.y = end.y = ul_corner->y;
793 renderer_ops->draw_line(renderer, &start, &end, color);
794 start.y = end.y = lr_corner->y;
795 renderer_ops->draw_line(renderer, &start, &end, color);
797 center.y = ul_corner->y+radius;
798 renderer_ops->draw_arc(renderer, &center,
799 2.0*radius, 2.0*radius,
800 90.0, 180.0, color);
801 center.x = end.x;
802 renderer_ops->draw_arc(renderer, &center,
803 2.0*radius, 2.0*radius,
804 0.0, 90.0, color);
806 start.y = ul_corner->y+radius;
807 start.x = end.x = ul_corner->x;
808 end.y = center.y = lr_corner->y-radius;
809 renderer_ops->draw_line(renderer, &start, &end, color);
810 start.x = end.x = lr_corner->x;
811 renderer_ops->draw_line(renderer, &start, &end, color);
813 center.y = lr_corner->y-radius;
814 center.x = ul_corner->x+radius;
815 renderer_ops->draw_arc(renderer, &center,
816 2.0*radius, 2.0*radius,
817 180.0, 270.0, color);
818 center.x = lr_corner->x-radius;
819 renderer_ops->draw_arc(renderer, &center,
820 2.0*radius, 2.0*radius,
821 270.0, 360.0, color);
824 static void
825 fill_rounded_rect(DiaRenderer *renderer,
826 Point *ul_corner, Point *lr_corner,
827 Color *color, real radius)
829 DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
830 Point start, end, center;
832 radius = MIN(radius, (lr_corner->x-ul_corner->x)/2);
833 radius = MIN(radius, (lr_corner->y-ul_corner->y)/2);
834 start.x = center.x = ul_corner->x+radius;
835 end.x = lr_corner->x-radius;
836 start.y = ul_corner->y;
837 end.y = lr_corner->y;
838 renderer_ops->fill_rect(renderer, &start, &end, color);
840 center.y = ul_corner->y+radius;
841 renderer_ops->fill_arc(renderer, &center,
842 2.0*radius, 2.0*radius,
843 90.0, 180.0, color);
844 center.x = end.x;
845 renderer_ops->fill_arc(renderer, &center,
846 2.0*radius, 2.0*radius,
847 0.0, 90.0, color);
850 start.x = ul_corner->x;
851 start.y = ul_corner->y+radius;
852 end.x = lr_corner->x;
853 end.y = center.y = lr_corner->y-radius;
854 renderer_ops->fill_rect(renderer, &start, &end, color);
856 center.y = lr_corner->y-radius;
857 center.x = ul_corner->x+radius;
858 renderer_ops->fill_arc(renderer, &center,
859 2.0*radius, 2.0*radius,
860 180.0, 270.0, color);
861 center.x = lr_corner->x-radius;
862 renderer_ops->fill_arc(renderer, &center,
863 2.0*radius, 2.0*radius,
864 270.0, 360.0, color);
867 static void
868 draw_line_with_arrows(DiaRenderer *renderer,
869 Point *startpoint,
870 Point *endpoint,
871 real line_width,
872 Color *color,
873 Arrow *start_arrow,
874 Arrow *end_arrow)
876 Point oldstart = *startpoint;
877 Point oldend = *endpoint;
878 Point start_arrow_head;
879 Point end_arrow_head;
881 /* Calculate how to more the line to account for arrow heads */
882 if (start_arrow != NULL && start_arrow->type != ARROW_NONE) {
883 Point move_arrow, move_line;
884 calculate_arrow_point(start_arrow, startpoint, endpoint,
885 &move_arrow, &move_line,
886 line_width);
887 start_arrow_head = *startpoint;
888 point_sub(&start_arrow_head, &move_arrow);
889 point_sub(startpoint, &move_line);
891 if (end_arrow != NULL && end_arrow->type != ARROW_NONE) {
892 Point move_arrow, move_line;
893 calculate_arrow_point(end_arrow, endpoint, startpoint,
894 &move_arrow, &move_line,
895 line_width);
896 end_arrow_head = *endpoint;
897 point_sub(&end_arrow_head, &move_arrow);
898 point_sub(endpoint, &move_line);
901 DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer, startpoint, endpoint, color);
903 /* Actual arrow drawing down here so line styles aren't disturbed */
904 if (start_arrow != NULL && start_arrow->type != ARROW_NONE)
905 arrow_draw(renderer, start_arrow->type,
906 &start_arrow_head, endpoint,
907 start_arrow->length, start_arrow->width,
908 line_width,
909 color, &color_white);
910 if (end_arrow != NULL && end_arrow->type != ARROW_NONE)
911 arrow_draw(renderer, end_arrow->type,
912 &end_arrow_head, startpoint,
913 end_arrow->length, end_arrow->width,
914 line_width,
915 color, &color_white);
917 *startpoint = oldstart;
918 *endpoint = oldend;
921 static void
922 draw_polyline_with_arrows(DiaRenderer *renderer,
923 Point *points, int num_points,
924 real line_width,
925 Color *color,
926 Arrow *start_arrow,
927 Arrow *end_arrow)
929 /* Index of first and last point with a non-zero length segment */
930 int firstline = 0;
931 int lastline = num_points;
932 Point oldstart = points[firstline];
933 Point oldend = points[lastline-1];
934 Point start_arrow_head;
935 Point end_arrow_head;
937 if (start_arrow != NULL && start_arrow->type != ARROW_NONE) {
938 Point move_arrow, move_line;
939 while (firstline < num_points-1 &&
940 distance_point_point(&points[firstline],
941 &points[firstline+1]) < 0.0000001)
942 firstline++;
943 if (firstline == num_points-1)
944 firstline = 0; /* No non-zero lines, it doesn't matter. */
945 oldstart = points[firstline];
946 calculate_arrow_point(start_arrow,
947 &points[firstline], &points[firstline+1],
948 &move_arrow, &move_line,
949 line_width);
950 start_arrow_head = points[firstline];
951 point_sub(&start_arrow_head, &move_arrow);
952 point_sub(&points[firstline], &move_line);
954 if (end_arrow != NULL && end_arrow->type != ARROW_NONE) {
955 Point move_arrow, move_line;
956 while (lastline > 0 &&
957 distance_point_point(&points[lastline-1],
958 &points[lastline-2]) < 0.0000001)
959 lastline--;
960 if (lastline == 0)
961 firstline = num_points; /* No non-zero lines, it doesn't matter. */
962 oldend = points[lastline-1];
963 calculate_arrow_point(end_arrow, &points[lastline-1],
964 &points[lastline-2],
965 &move_arrow, &move_line,
966 line_width);
967 end_arrow_head = points[lastline-1];
968 point_sub(&end_arrow_head, &move_arrow);
969 point_sub(&points[lastline-1], &move_line);
971 /* Don't draw degenerate line segments at end of line */
972 if (lastline-firstline > 1) /* probably hiding a bug above, but don't try to draw a negative
973 * number of points at all, fixes bug #148139 */
974 DIA_RENDERER_GET_CLASS(renderer)->draw_polyline(renderer, &points[firstline],
975 lastline-firstline, color);
976 if (start_arrow != NULL && start_arrow->type != ARROW_NONE)
977 arrow_draw(renderer, start_arrow->type,
978 &start_arrow_head, &points[firstline+1],
979 start_arrow->length, start_arrow->width,
980 line_width,
981 color, &color_white);
982 if (end_arrow != NULL && end_arrow->type != ARROW_NONE)
983 arrow_draw(renderer, end_arrow->type,
984 &end_arrow_head, &points[lastline-2],
985 end_arrow->length, end_arrow->width,
986 line_width,
987 color, &color_white);
989 points[firstline] = oldstart;
990 points[lastline-1] = oldend;
993 static void
994 draw_rounded_polyline_with_arrows(DiaRenderer *renderer,
995 Point *points, int num_points,
996 real line_width,
997 Color *color,
998 Arrow *start_arrow,
999 Arrow *end_arrow,
1000 real radius)
1002 /* Index of first and last point with a non-zero length segment */
1003 int firstline = 0;
1004 int lastline = num_points;
1005 Point oldstart = points[firstline];
1006 Point oldend = points[lastline-1];
1007 Point start_arrow_head;
1008 Point end_arrow_head;
1010 if (start_arrow != NULL && start_arrow->type != ARROW_NONE) {
1011 Point move_arrow, move_line;
1012 while (firstline < num_points-1 &&
1013 distance_point_point(&points[firstline],
1014 &points[firstline+1]) < 0.0000001)
1015 firstline++;
1016 if (firstline == num_points-1)
1017 firstline = 0; /* No non-zero lines, it doesn't matter. */
1018 oldstart = points[firstline];
1019 calculate_arrow_point(start_arrow,
1020 &points[firstline], &points[firstline+1],
1021 &move_arrow, &move_line,
1022 line_width);
1023 start_arrow_head = points[firstline];
1024 point_sub(&start_arrow_head, &move_arrow);
1025 point_sub(&points[firstline], &move_line);
1027 if (end_arrow != NULL && end_arrow->type != ARROW_NONE) {
1028 Point move_arrow, move_line;
1029 while (lastline > 0 &&
1030 distance_point_point(&points[lastline-1],
1031 &points[lastline-2]) < 0.0000001)
1032 lastline--;
1033 if (lastline == 0)
1034 firstline = num_points; /* No non-zero lines, it doesn't matter. */
1035 oldend = points[lastline-1];
1036 calculate_arrow_point(end_arrow, &points[lastline-1],
1037 &points[lastline-2],
1038 &move_arrow, &move_line,
1039 line_width);
1040 end_arrow_head = points[lastline-1];
1041 point_sub(&end_arrow_head, &move_arrow);
1042 point_sub(&points[lastline-1], &move_line);
1044 /* Don't draw degenerate line segments at end of line */
1045 if (lastline-firstline > 1) /* only if there is something */
1046 DIA_RENDERER_GET_CLASS(renderer)->draw_rounded_polyline(renderer,
1047 &points[firstline],
1048 lastline-firstline,
1049 color, radius);
1050 if (start_arrow != NULL && start_arrow->type != ARROW_NONE)
1051 arrow_draw(renderer, start_arrow->type,
1052 &start_arrow_head, &points[firstline+1],
1053 start_arrow->length, start_arrow->width,
1054 line_width,
1055 color, &color_white);
1056 if (end_arrow != NULL && end_arrow->type != ARROW_NONE)
1057 arrow_draw(renderer, end_arrow->type,
1058 &end_arrow_head, &points[lastline-2],
1059 end_arrow->length, end_arrow->width,
1060 line_width,
1061 color, &color_white);
1063 points[firstline] = oldstart;
1064 points[lastline-1] = oldend;
1067 /** Figure the equation for a line given by two points.
1068 * Returns FALSE if the line is vertical (infinite a).
1070 static gboolean
1071 points_to_line(real *a, real *b, Point *p1, Point *p2)
1073 if (fabs(p1->x - p2->x) < 0.000000001)
1074 return FALSE;
1075 *a = (p2->y-p1->y)/(p2->x-p1->x);
1076 *b = p1->y-(*a)*p1->x;
1077 return TRUE;
1080 /** Find the intersection between two lines.
1081 * Returns TRUE if the lines intersect in a single point.
1083 static gboolean
1084 intersection_line_line(Point *cross,
1085 Point *p1a, Point *p1b,
1086 Point *p2a, Point *p2b)
1088 real a1, b1, a2, b2;
1090 /* Find coefficients of lines */
1091 if (!(points_to_line(&a1, &b1, p1a, p1b))) {
1092 if (!(points_to_line(&a2, &b2, p2a, p2b))) {
1093 if (fabs(p1a->x-p2a->x) < 0.00000001) {
1094 *cross = *p1a;
1095 return TRUE;
1096 } else return FALSE;
1098 cross->x = p1a->x;
1099 cross->y = a2*(p1a->x)+b2;
1100 return TRUE;
1102 if (!(points_to_line(&a2, &b2, p2a, p2b))) {
1103 cross->x = p2a->x;
1104 cross->y = a1*(p2a->x)+b1;
1105 return TRUE;
1107 /* Solve */
1108 if (fabs(a1-a2) < 0.000000001) {
1109 if (fabs(b1-b2) < 0.000000001) {
1110 *cross = *p1a;
1111 return TRUE;
1112 } else {
1113 return FALSE;
1115 } else {
1117 a1x+b1 = a2x+b2;
1118 a1x = a2x+b2-b1;
1119 a1x-a2x = b2-b1;
1120 (a1-a2)x = b2-b1;
1121 x = (b2-b1)/(a1-a2)
1123 cross->x = (b2-b1)/(a1-a2);
1124 cross->y = a1*cross->x+b1;
1125 return TRUE;
1129 /** Given three points, find the center of the circle they describe.
1130 * Returns FALSE if the center could not be determined (i.e. the points
1131 * all lie really close together).
1132 * The renderer should disappear once the debugging is done.
1134 static gboolean
1135 find_center_point(Point *center, Point *p1, Point *p2, Point *p3)
1137 Point mid1;
1138 Point mid2;
1139 Point orth1;
1140 Point orth2;
1141 real tmp;
1143 /* Find vector from middle between two points towards center */
1144 mid1 = *p1;
1145 point_sub(&mid1, p2);
1146 point_scale(&mid1, 0.5);
1147 orth1 = mid1;
1148 point_add(&mid1, p2); /* Now midpoint between p1 & p2 */
1149 tmp = orth1.x;
1150 orth1.x = orth1.y;
1151 orth1.y = -tmp;
1152 point_add(&orth1, &mid1);
1155 /* Again, with two other points */
1156 mid2 = *p2;
1157 point_sub(&mid2, p3);
1158 point_scale(&mid2, 0.5);
1159 orth2 = mid2;
1160 point_add(&mid2, p3); /* Now midpoint between p2 & p3 */
1161 tmp = orth2.x;
1162 orth2.x = orth2.y;
1163 orth2.y = -tmp;
1164 point_add(&orth2, &mid2);
1166 /* The intersection between these two is the center */
1167 if (!intersection_line_line(center, &mid1, &orth1, &mid2, &orth2)) {
1168 /* Degenerate circle */
1169 /* Case 1: Points are all on top of each other. Nothing to do. */
1170 if (fabs((p1->x + p2->x + p3->x)/3 - p1->x) < 0.0000001 &&
1171 fabs((p1->y + p2->y + p3->y)/3 - p1->y) < 0.0000001) {
1172 return FALSE;
1175 /* Case 2: Two points are on top of each other. Midpoint of
1176 * non-degenerate line is center. */
1177 if (distance_point_point_manhattan(p1, p2) < 0.0000001) {
1178 *center = mid2;
1179 return TRUE;
1180 } else if (distance_point_point_manhattan(p1, p3) < 0.0000001 ||
1181 distance_point_point_manhattan(p2, p3) < 0.0000001) {
1182 *center = mid1;
1183 return TRUE;
1185 /* Case 3: All points on a line. Nothing to do. */
1186 return FALSE;
1188 return TRUE;
1191 static gboolean
1192 is_right_hand (const Point *a, const Point *b, const Point *c)
1194 Point dot1, dot2;
1196 dot1 = *a;
1197 point_sub(&dot1, c);
1198 point_normalize(&dot1);
1199 dot2 = *b;
1200 point_sub(&dot2, c);
1201 point_normalize(&dot2);
1202 return point_cross(&dot1, &dot2) > 0;
1205 static void
1206 draw_arc_with_arrows (DiaRenderer *renderer,
1207 Point *startpoint,
1208 Point *endpoint,
1209 Point *midpoint,
1210 real line_width,
1211 Color *color,
1212 Arrow *start_arrow,
1213 Arrow *end_arrow)
1215 Point oldstart = *startpoint;
1216 Point oldend = *endpoint;
1217 Point center;
1218 real width, angle1, angle2, arrow_ofs = 0.0;
1219 gboolean righthand;
1220 Point start_arrow_head;
1221 Point start_arrow_end;
1222 Point end_arrow_head;
1223 Point end_arrow_end;
1225 if (!find_center_point(&center, startpoint, endpoint, midpoint)) {
1226 /* Degenerate circle -- should have been caught by the drawer? */
1227 printf("Degenerate\n");
1230 righthand = is_right_hand (startpoint, midpoint, endpoint);
1232 width = 2*distance_point_point(&center, startpoint);
1234 if (start_arrow != NULL && start_arrow->type != ARROW_NONE) {
1235 Point move_arrow, move_line;
1236 real tmp;
1238 start_arrow_end = *startpoint;
1239 point_sub(&start_arrow_end, &center);
1240 tmp = start_arrow_end.x;
1241 if (righthand) {
1242 start_arrow_end.x = -start_arrow_end.y;
1243 start_arrow_end.y = tmp;
1244 } else {
1245 start_arrow_end.x = start_arrow_end.y;
1246 start_arrow_end.y = -tmp;
1248 point_add(&start_arrow_end, startpoint);
1250 calculate_arrow_point(start_arrow, startpoint, &start_arrow_end,
1251 &move_arrow, &move_line,
1252 line_width);
1253 start_arrow_head = *startpoint;
1254 point_sub(&start_arrow_head, &move_arrow);
1255 point_sub(startpoint, &move_line);
1256 arrow_ofs += sqrt (move_line.x * move_line.x + move_line.y * move_line.y);
1258 if (end_arrow != NULL && end_arrow->type != ARROW_NONE) {
1259 Point move_arrow, move_line;
1260 real tmp;
1262 end_arrow_end = *endpoint;
1263 point_sub(&end_arrow_end, &center);
1264 tmp = end_arrow_end.x;
1265 if (righthand) {
1266 end_arrow_end.x = end_arrow_end.y;
1267 end_arrow_end.y = -tmp;
1268 } else {
1269 end_arrow_end.x = -end_arrow_end.y;
1270 end_arrow_end.y = tmp;
1272 point_add(&end_arrow_end, endpoint);
1274 calculate_arrow_point(end_arrow, endpoint, &end_arrow_end,
1275 &move_arrow, &move_line,
1276 line_width);
1277 end_arrow_head = *endpoint;
1278 point_sub(&end_arrow_head, &move_arrow);
1279 point_sub(endpoint, &move_line);
1280 arrow_ofs += sqrt (move_line.x * move_line.x + move_line.y * move_line.y);
1283 /* Now we possibly have new start- and endpoint. We must not
1284 * recalculate the center cause the new points lie on the tangential
1285 * approximation of the original arc arrow lines not on the arc itself.
1286 * The one thing we need to deal with is calculating the (new) angles
1287 * and get rid of the arc drawing altogether if got degenerated.
1289 * Why shouldn't we recalculate the whole thing from the new start/endpoints?
1290 * Done this way the arc does not come out the back of the arrows.
1291 * -LC, 20/2/2006
1293 angle1 = -atan2(startpoint->y - center.y, startpoint->x - center.x)*180.0/G_PI;
1294 while (angle1 < 0.0) angle1 += 360.0;
1295 angle2 = -atan2(endpoint->y - center.y, endpoint->x - center.x)*180.0/G_PI;
1296 while (angle2 < 0.0) angle2 += 360.0;
1297 if (righthand) {
1298 real tmp = angle1;
1299 angle1 = angle2;
1300 angle2 = tmp;
1302 /* now with the angles we can bring the startpoint back to the arc, but there must be a less expensive way to do this? */
1303 if (start_arrow != NULL && start_arrow->type != ARROW_NONE) {
1304 startpoint->x = cos (G_PI * angle1 / 180.0) * width / 2.0 + center.x;
1305 startpoint->y = sin (G_PI * angle1 / 180.0) * width / 2.0 + center.y;
1307 if (end_arrow != NULL && end_arrow->type != ARROW_NONE) {
1308 endpoint->x = cos (G_PI * angle1 / 180.0) * width / 2.0 + center.x;
1309 endpoint->y = sin (G_PI * angle1 / 180.0) * width / 2.0 + center.y;
1312 DIA_RENDERER_GET_CLASS(renderer)->draw_arc(renderer, &center, width, width,
1313 angle1, angle2, color);
1315 if (start_arrow != NULL && start_arrow->type != ARROW_NONE)
1316 arrow_draw(renderer, start_arrow->type,
1317 &start_arrow_head, &start_arrow_end,
1318 start_arrow->length, start_arrow->width,
1319 line_width,
1320 color, &color_white);
1321 if (end_arrow != NULL && end_arrow->type != ARROW_NONE)
1322 arrow_draw(renderer, end_arrow->type,
1323 &end_arrow_head, &end_arrow_end,
1324 end_arrow->length, end_arrow->width,
1325 line_width,
1326 color, &color_white);
1328 *startpoint = oldstart;
1329 *endpoint = oldend;
1332 static void
1333 draw_bezier_with_arrows(DiaRenderer *renderer,
1334 BezPoint *points,
1335 int num_points,
1336 real line_width,
1337 Color *color,
1338 Arrow *start_arrow,
1339 Arrow *end_arrow)
1341 Point startpoint, endpoint;
1342 Point start_arrow_head;
1343 Point end_arrow_head;
1345 startpoint = points[0].p1;
1346 endpoint = points[num_points-1].p3;
1348 if (start_arrow != NULL && start_arrow->type != ARROW_NONE) {
1349 Point move_arrow;
1350 Point move_line;
1351 calculate_arrow_point(start_arrow, &points[0].p1, &points[1].p1,
1352 &move_arrow, &move_line,
1353 line_width);
1354 start_arrow_head = points[0].p1;
1355 point_sub(&start_arrow_head, &move_arrow);
1356 point_sub(&points[0].p1, &move_line);
1358 if (end_arrow != NULL && end_arrow->type != ARROW_NONE) {
1359 Point move_arrow;
1360 Point move_line;
1361 calculate_arrow_point(end_arrow,
1362 &points[num_points-1].p3, &points[num_points-1].p2,
1363 &move_arrow, &move_line,
1364 line_width);
1365 end_arrow_head = points[num_points-1].p3;
1366 point_sub(&end_arrow_head, &move_arrow);
1367 point_sub(&points[num_points-1].p3, &move_line);
1369 DIA_RENDERER_GET_CLASS(renderer)->draw_bezier(renderer, points, num_points, color);
1370 if (start_arrow != NULL && start_arrow->type != ARROW_NONE)
1371 arrow_draw(renderer, start_arrow->type,
1372 &start_arrow_head, &points[1].p1,
1373 start_arrow->length, start_arrow->width,
1374 line_width,
1375 color, &color_white);
1376 if (end_arrow != NULL && end_arrow->type != ARROW_NONE)
1377 arrow_draw(renderer, end_arrow->type,
1378 &end_arrow_head, &points[num_points-1].p2,
1379 end_arrow->length, end_arrow->width,
1380 line_width,
1381 color, &color_white);
1383 points[0].p1 = startpoint;
1384 points[num_points-1].p3 = endpoint;
1389 * Should we really provide this ? It formerly was an 'interactive op'
1390 * and depends on DiaRenderer::set_font() not or properly overwritten
1392 static real
1393 get_text_width (DiaRenderer *renderer,
1394 const gchar *text, int length)
1396 real ret = 0;
1398 if (renderer->font) {
1399 char *str = g_strndup (text, length);
1401 ret = dia_font_string_width (str,
1402 renderer->font,
1403 renderer->font_height);
1404 g_free (str);
1407 return ret;
1410 static int
1411 get_width_pixels (DiaRenderer *renderer)
1413 g_return_val_if_fail (renderer->is_interactive, 0);
1414 return 0;
1417 static int
1418 get_height_pixels (DiaRenderer *renderer)
1420 g_return_val_if_fail (renderer->is_interactive, 0);
1421 return 0;
1426 * non member functions
1429 dia_renderer_get_width_pixels (DiaRenderer *renderer)
1431 return DIA_RENDERER_GET_CLASS(renderer)->get_width_pixels (renderer);
1435 dia_renderer_get_height_pixels (DiaRenderer *renderer)
1437 return DIA_RENDERER_GET_CLASS(renderer)->get_height_pixels (renderer);