* lib/text.h: Added text_get_line() declaration
[dia.git] / lib / diarenderer.c
blob5444ab40915503abcb3d012de3e8894aaa3664e2
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;
408 #ifdef USE_TEXTLINE_FOR_LINES
409 pos = text->position;
411 for (i=0;i<text->numlines;i++) {
412 Point aligned_pos = pos;
413 aligned_pos.x -= text_line_get_alignment_adjustment(text->lines[i],
414 text->alignment);
415 DIA_RENDERER_GET_CLASS(renderer)->draw_text_line(renderer,
416 text->lines[i],
417 &aligned_pos,
418 &text->color);
419 pos.y += text->height;
421 #else
422 DIA_RENDERER_GET_CLASS(renderer)->set_font(renderer, text->font, text->height);
424 pos = text->position;
426 for (i=0;i<text->numlines;i++) {
427 DIA_RENDERER_GET_CLASS(renderer)->draw_string(renderer,
428 text->line[i],
429 &pos, text->alignment,
430 &text->color);
431 pos.y += text->height;
433 #endif
436 /** Default implementation of draw_text_line */
437 static void draw_text_line(DiaRenderer *renderer,
438 TextLine *text_line, Point *pos, Color *color) {
439 DIA_RENDERER_GET_CLASS(renderer)->set_font(renderer,
440 text_line_get_font(text_line),
441 text_line_get_height(text_line));
443 DIA_RENDERER_GET_CLASS(renderer)->draw_string(renderer,
444 text_line_get_string(text_line),
445 pos, ALIGN_LEFT,
446 color);
449 static void
450 draw_image (DiaRenderer *renderer,
451 Point *point, real width, real height,
452 DiaImage image)
454 g_warning ("%s::draw_image not implemented!",
455 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
460 * medium level functions, implemented by the above
462 /* Bezier implementation notes:
463 * These beziers have the following basis matrix:
464 * [-1 3 -3 1]
465 * [ 3 -6 3 0]
466 * [-3 3 0 0]
467 * [ 1 0 0 0]
468 * (At least that's what Hearn and Baker says for beziers.)
470 #define BEZIER_SUBDIVIDE_LIMIT 0.01
471 #define BEZIER_SUBDIVIDE_LIMIT_SQ (BEZIER_SUBDIVIDE_LIMIT*BEZIER_SUBDIVIDE_LIMIT)
473 static void
474 bezier_add_point(BezierApprox *bezier,
475 Point *point)
477 /* Grow if needed: */
478 if (bezier->currpoint == bezier->numpoints) {
479 bezier->numpoints += 40;
480 bezier->points = g_realloc(bezier->points,
481 bezier->numpoints*sizeof(Point));
484 bezier->points[bezier->currpoint] = *point;
486 bezier->currpoint++;
489 static void
490 bezier_add_lines(BezierApprox *bezier,
491 Point points[4])
493 Point u, v, x, y;
494 Point r[4];
495 Point s[4];
496 Point middle;
497 coord delta;
498 real v_len_sq;
500 /* Check if almost flat: */
501 u = points[1];
502 point_sub(&u, &points[0]);
503 v = points[3];
504 point_sub(&v, &points[0]);
505 y = v;
506 v_len_sq = point_dot(&v,&v);
507 if (isnan(v_len_sq)) {
508 g_warning("v_len_sq is NaN while calculating bezier curve!");
509 return;
511 if (v_len_sq < 0.000001)
512 v_len_sq = 0.000001;
513 point_scale(&y, point_dot(&u,&v)/v_len_sq);
514 x = u;
515 point_sub(&x,&y);
516 delta = point_dot(&x,&x);
517 if (delta < BEZIER_SUBDIVIDE_LIMIT_SQ) {
518 u = points[2];
519 point_sub(&u, &points[3]);
520 v = points[0];
521 point_sub(&v, &points[3]);
522 y = v;
523 v_len_sq = point_dot(&v,&v);
524 if (v_len_sq < 0.000001)
525 v_len_sq = 0.000001;
526 point_scale(&y, point_dot(&u,&v)/v_len_sq);
527 x = u;
528 point_sub(&x,&y);
529 delta = point_dot(&x,&x);
530 if (delta < BEZIER_SUBDIVIDE_LIMIT_SQ) { /* Almost flat, draw a line */
531 bezier_add_point(bezier, &points[3]);
532 return;
535 /* Subdivide into two bezier curves: */
537 middle = points[1];
538 point_add(&middle, &points[2]);
539 point_scale(&middle, 0.5);
541 r[0] = points[0];
543 r[1] = points[0];
544 point_add(&r[1], &points[1]);
545 point_scale(&r[1], 0.5);
547 r[2] = r[1];
548 point_add(&r[2], &middle);
549 point_scale(&r[2], 0.5);
551 s[3] = points[3];
553 s[2] = points[2];
554 point_add(&s[2], &points[3]);
555 point_scale(&s[2], 0.5);
557 s[1] = s[2];
558 point_add(&s[1], &middle);
559 point_scale(&s[1], 0.5);
561 r[3] = r[2];
562 point_add(&r[3], &s[1]);
563 point_scale(&r[3], 0.5);
565 s[0] = r[3];
567 bezier_add_lines(bezier, r);
568 bezier_add_lines(bezier, s);
571 static void
572 bezier_add_curve(BezierApprox *bezier,
573 Point points[4])
575 /* Is the bezier curve malformed? */
576 if ( (distance_point_point(&points[0], &points[1]) < 0.00001) &&
577 (distance_point_point(&points[2], &points[3]) < 0.00001) &&
578 (distance_point_point(&points[0], &points[3]) < 0.00001)) {
579 bezier_add_point(bezier, &points[3]);
582 bezier_add_lines(bezier, points);
585 static void
586 approximate_bezier (BezierApprox *bezier,
587 BezPoint *points, int numpoints)
589 Point curve[4];
590 int i;
592 if (points[0].type != BEZ_MOVE_TO)
593 g_warning("first BezPoint must be a BEZ_MOVE_TO");
594 curve[3] = points[0].p1;
595 bezier_add_point(bezier, &points[0].p1);
596 for (i = 1; i < numpoints; i++)
597 switch (points[i].type) {
598 case BEZ_MOVE_TO:
599 g_warning("only first BezPoint can be a BEZ_MOVE_TO");
600 curve[3] = points[i].p1;
601 break;
602 case BEZ_LINE_TO:
603 bezier_add_point(bezier, &points[i].p1);
604 curve[3] = points[i].p1;
605 break;
606 case BEZ_CURVE_TO:
607 curve[0] = curve[3];
608 curve[1] = points[i].p1;
609 curve[2] = points[i].p2;
610 curve[3] = points[i].p3;
611 bezier_add_curve(bezier, curve);
612 break;
616 /* bezier approximation with straight lines */
617 static void
618 draw_bezier (DiaRenderer *renderer,
619 BezPoint *points, int numpoints,
620 Color *color)
622 BezierApprox *bezier;
624 if (renderer->bezier)
625 bezier = renderer->bezier;
626 else
627 renderer->bezier = bezier = g_new0 (BezierApprox, 1);
629 if (bezier->points == NULL) {
630 bezier->numpoints = 30;
631 bezier->points = g_malloc(bezier->numpoints*sizeof(Point));
634 bezier->currpoint = 0;
635 approximate_bezier (bezier, points, numpoints);
637 DIA_RENDERER_GET_CLASS (renderer)->draw_polyline (renderer,
638 bezier->points,
639 bezier->currpoint,
640 color);
643 static void
644 fill_bezier (DiaRenderer *renderer,
645 BezPoint *points, int numpoints,
646 Color *color)
648 BezierApprox *bezier;
650 if (renderer->bezier)
651 bezier = renderer->bezier;
652 else
653 renderer->bezier = bezier = g_new0 (BezierApprox, 1);
655 if (bezier->points == NULL) {
656 bezier->numpoints = 30;
657 bezier->points = g_malloc(bezier->numpoints*sizeof(Point));
660 bezier->currpoint = 0;
661 approximate_bezier (bezier, points, numpoints);
663 DIA_RENDERER_GET_CLASS (renderer)->fill_polygon (renderer,
664 bezier->points,
665 bezier->currpoint,
666 color);
669 static void
670 draw_rect (DiaRenderer *renderer,
671 Point *ul_corner, Point *lr_corner,
672 Color *color)
674 DiaRendererClass *klass = DIA_RENDERER_GET_CLASS (renderer);
675 Point ur, ll;
677 ur.x = lr_corner->x;
678 ur.y = ul_corner->y;
679 ll.x = ul_corner->x;
680 ll.y = lr_corner->y;
682 klass->draw_line (renderer, ul_corner, &ur, color);
683 klass->draw_line (renderer, &ur, lr_corner, color);
684 klass->draw_line (renderer, lr_corner, &ll, color);
685 klass->draw_line (renderer, &ll, ul_corner, color);
688 static void
689 draw_polyline (DiaRenderer *renderer,
690 Point *points, int num_points,
691 Color *color)
693 DiaRendererClass *klass = DIA_RENDERER_GET_CLASS (renderer);
694 int i;
696 for (i = 0; i < num_points - 1; i++)
697 klass->draw_line (renderer, &points[i+0], &points[i+1], color);
701 /* calculate the maximum possible radius for 3 points
702 use the following,
703 given points p1,p2, and p3
704 let c = min(length(p1,p2)/2,length(p2,p3)/2)
705 let a = dot2(p1-p2, p3-p2)
706 (ie, angle between lines p1,p2 and p2,p3)
707 then maxr = c * sin(a/2)
709 static real
710 calculate_min_radius( Point *p1, Point *p2, Point *p3 )
712 real c;
713 real a;
714 Point v1,v2;
716 c = MIN(distance_point_point(p1,p2)/2,distance_point_point(p2,p3)/2);
717 v1.x = p1->x-p2->x; v1.y = p1->y-p2->y;
718 v2.x = p3->x-p2->x; v2.y = p3->y-p2->y;
719 a = dot2(&v1,&v2);
720 return (c*sin(a/2));
723 /** Draw a polyline with optionally rounded corners.
724 * Based on draw_line and draw_arc, but uses draw_polyline when
725 * the rounding is too small.
727 static void
728 draw_rounded_polyline (DiaRenderer *renderer,
729 Point *points, int num_points,
730 Color *color, real radius)
732 DiaRendererClass *klass = DIA_RENDERER_GET_CLASS (renderer);
733 int i = 0;
734 Point p1,p2,p3,p4 ;
735 Point *p;
736 p = points;
738 if (radius < 0.00001) {
739 klass->draw_polyline(renderer, points, num_points, color);
740 return;
743 /* skip arc computations if we only have points */
744 if ( num_points <= 2 ) {
745 i = 0;
746 p1.x = p[i].x; p1.y = p[i].y;
747 p2.x = p[i+1].x; p2.y = p[i+1].y;
748 klass->draw_line(renderer,&p1,&p2,color);
749 return;
752 i = 0;
753 /* full rendering 3 or more points */
754 p1.x = p[i].x; p1.y = p[i].y;
755 p2.x = p[i+1].x; p2.y = p[i+1].y;
756 for (i = 0; i <= num_points - 3; i++) {
757 Point c;
758 real start_angle, stop_angle;
759 real min_radius;
760 p3.x = p[i+1].x; p3.y = p[i+1].y;
761 p4.x = p[i+2].x; p4.y = p[i+2].y;
763 /* adjust the radius if it would cause odd rendering */
764 min_radius = MIN(radius, calculate_min_radius(&p1,&p2,&p4));
765 fillet(&p1,&p2,&p3,&p4, min_radius, &c, &start_angle, &stop_angle);
766 klass->draw_arc(renderer, &c, min_radius*2, min_radius*2,
767 start_angle,
768 stop_angle, color);
769 klass->draw_line(renderer, &p1, &p2, color);
770 p1.x = p3.x; p1.y = p3.y;
771 p2.x = p4.x; p2.y = p4.y;
773 klass->draw_line(renderer, &p3, &p4, color);
776 static void
777 draw_polygon (DiaRenderer *renderer,
778 Point *points, int num_points,
779 Color *color)
781 DiaRendererClass *klass = DIA_RENDERER_GET_CLASS (renderer);
782 int i;
784 g_return_if_fail (num_points > 1);
786 for (i = 0; i < num_points - 1; i++)
787 klass->draw_line (renderer, &points[i+0], &points[i+1], color);
788 /* close it in any case */
789 if ( (points[0].x != points[num_points-1].x)
790 || (points[0].y != points[num_points-1].y))
791 klass->draw_line (renderer, &points[num_points-1], &points[0], color);
794 static void
795 draw_rounded_rect (DiaRenderer *renderer,
796 Point *ul_corner, Point *lr_corner,
797 Color *color, real radius)
799 DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
800 Point start, end, center;
802 radius = MIN(radius, (lr_corner->x-ul_corner->x)/2);
803 radius = MIN(radius, (lr_corner->y-ul_corner->y)/2);
804 start.x = center.x = ul_corner->x+radius;
805 end.x = lr_corner->x-radius;
806 start.y = end.y = ul_corner->y;
807 renderer_ops->draw_line(renderer, &start, &end, color);
808 start.y = end.y = lr_corner->y;
809 renderer_ops->draw_line(renderer, &start, &end, color);
811 center.y = ul_corner->y+radius;
812 renderer_ops->draw_arc(renderer, &center,
813 2.0*radius, 2.0*radius,
814 90.0, 180.0, color);
815 center.x = end.x;
816 renderer_ops->draw_arc(renderer, &center,
817 2.0*radius, 2.0*radius,
818 0.0, 90.0, color);
820 start.y = ul_corner->y+radius;
821 start.x = end.x = ul_corner->x;
822 end.y = center.y = lr_corner->y-radius;
823 renderer_ops->draw_line(renderer, &start, &end, color);
824 start.x = end.x = lr_corner->x;
825 renderer_ops->draw_line(renderer, &start, &end, color);
827 center.y = lr_corner->y-radius;
828 center.x = ul_corner->x+radius;
829 renderer_ops->draw_arc(renderer, &center,
830 2.0*radius, 2.0*radius,
831 180.0, 270.0, color);
832 center.x = lr_corner->x-radius;
833 renderer_ops->draw_arc(renderer, &center,
834 2.0*radius, 2.0*radius,
835 270.0, 360.0, color);
838 static void
839 fill_rounded_rect(DiaRenderer *renderer,
840 Point *ul_corner, Point *lr_corner,
841 Color *color, real radius)
843 DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer);
844 Point start, end, center;
846 radius = MIN(radius, (lr_corner->x-ul_corner->x)/2);
847 radius = MIN(radius, (lr_corner->y-ul_corner->y)/2);
848 start.x = center.x = ul_corner->x+radius;
849 end.x = lr_corner->x-radius;
850 start.y = ul_corner->y;
851 end.y = lr_corner->y;
852 renderer_ops->fill_rect(renderer, &start, &end, color);
854 center.y = ul_corner->y+radius;
855 renderer_ops->fill_arc(renderer, &center,
856 2.0*radius, 2.0*radius,
857 90.0, 180.0, color);
858 center.x = end.x;
859 renderer_ops->fill_arc(renderer, &center,
860 2.0*radius, 2.0*radius,
861 0.0, 90.0, color);
864 start.x = ul_corner->x;
865 start.y = ul_corner->y+radius;
866 end.x = lr_corner->x;
867 end.y = center.y = lr_corner->y-radius;
868 renderer_ops->fill_rect(renderer, &start, &end, color);
870 center.y = lr_corner->y-radius;
871 center.x = ul_corner->x+radius;
872 renderer_ops->fill_arc(renderer, &center,
873 2.0*radius, 2.0*radius,
874 180.0, 270.0, color);
875 center.x = lr_corner->x-radius;
876 renderer_ops->fill_arc(renderer, &center,
877 2.0*radius, 2.0*radius,
878 270.0, 360.0, color);
881 static void
882 draw_line_with_arrows(DiaRenderer *renderer,
883 Point *startpoint,
884 Point *endpoint,
885 real line_width,
886 Color *color,
887 Arrow *start_arrow,
888 Arrow *end_arrow)
890 Point oldstart = *startpoint;
891 Point oldend = *endpoint;
892 Point start_arrow_head;
893 Point end_arrow_head;
895 /* Calculate how to more the line to account for arrow heads */
896 if (start_arrow != NULL && start_arrow->type != ARROW_NONE) {
897 Point move_arrow, move_line;
898 calculate_arrow_point(start_arrow, startpoint, endpoint,
899 &move_arrow, &move_line,
900 line_width);
901 start_arrow_head = *startpoint;
902 point_sub(&start_arrow_head, &move_arrow);
903 point_sub(startpoint, &move_line);
905 if (end_arrow != NULL && end_arrow->type != ARROW_NONE) {
906 Point move_arrow, move_line;
907 calculate_arrow_point(end_arrow, endpoint, startpoint,
908 &move_arrow, &move_line,
909 line_width);
910 end_arrow_head = *endpoint;
911 point_sub(&end_arrow_head, &move_arrow);
912 point_sub(endpoint, &move_line);
915 DIA_RENDERER_GET_CLASS(renderer)->draw_line(renderer, startpoint, endpoint, color);
917 /* Actual arrow drawing down here so line styles aren't disturbed */
918 if (start_arrow != NULL && start_arrow->type != ARROW_NONE)
919 arrow_draw(renderer, start_arrow->type,
920 &start_arrow_head, endpoint,
921 start_arrow->length, start_arrow->width,
922 line_width,
923 color, &color_white);
924 if (end_arrow != NULL && end_arrow->type != ARROW_NONE)
925 arrow_draw(renderer, end_arrow->type,
926 &end_arrow_head, startpoint,
927 end_arrow->length, end_arrow->width,
928 line_width,
929 color, &color_white);
931 *startpoint = oldstart;
932 *endpoint = oldend;
935 static void
936 draw_polyline_with_arrows(DiaRenderer *renderer,
937 Point *points, int num_points,
938 real line_width,
939 Color *color,
940 Arrow *start_arrow,
941 Arrow *end_arrow)
943 /* Index of first and last point with a non-zero length segment */
944 int firstline = 0;
945 int lastline = num_points;
946 Point oldstart = points[firstline];
947 Point oldend = points[lastline-1];
948 Point start_arrow_head;
949 Point end_arrow_head;
951 if (start_arrow != NULL && start_arrow->type != ARROW_NONE) {
952 Point move_arrow, move_line;
953 while (firstline < num_points-1 &&
954 distance_point_point(&points[firstline],
955 &points[firstline+1]) < 0.0000001)
956 firstline++;
957 if (firstline == num_points-1)
958 firstline = 0; /* No non-zero lines, it doesn't matter. */
959 oldstart = points[firstline];
960 calculate_arrow_point(start_arrow,
961 &points[firstline], &points[firstline+1],
962 &move_arrow, &move_line,
963 line_width);
964 start_arrow_head = points[firstline];
965 point_sub(&start_arrow_head, &move_arrow);
966 point_sub(&points[firstline], &move_line);
968 if (end_arrow != NULL && end_arrow->type != ARROW_NONE) {
969 Point move_arrow, move_line;
970 while (lastline > 0 &&
971 distance_point_point(&points[lastline-1],
972 &points[lastline-2]) < 0.0000001)
973 lastline--;
974 if (lastline == 0)
975 firstline = num_points; /* No non-zero lines, it doesn't matter. */
976 oldend = points[lastline-1];
977 calculate_arrow_point(end_arrow, &points[lastline-1],
978 &points[lastline-2],
979 &move_arrow, &move_line,
980 line_width);
981 end_arrow_head = points[lastline-1];
982 point_sub(&end_arrow_head, &move_arrow);
983 point_sub(&points[lastline-1], &move_line);
985 /* Don't draw degenerate line segments at end of line */
986 if (lastline-firstline > 1) /* probably hiding a bug above, but don't try to draw a negative
987 * number of points at all, fixes bug #148139 */
988 DIA_RENDERER_GET_CLASS(renderer)->draw_polyline(renderer, &points[firstline],
989 lastline-firstline, color);
990 if (start_arrow != NULL && start_arrow->type != ARROW_NONE)
991 arrow_draw(renderer, start_arrow->type,
992 &start_arrow_head, &points[firstline+1],
993 start_arrow->length, start_arrow->width,
994 line_width,
995 color, &color_white);
996 if (end_arrow != NULL && end_arrow->type != ARROW_NONE)
997 arrow_draw(renderer, end_arrow->type,
998 &end_arrow_head, &points[lastline-2],
999 end_arrow->length, end_arrow->width,
1000 line_width,
1001 color, &color_white);
1003 points[firstline] = oldstart;
1004 points[lastline-1] = oldend;
1007 static void
1008 draw_rounded_polyline_with_arrows(DiaRenderer *renderer,
1009 Point *points, int num_points,
1010 real line_width,
1011 Color *color,
1012 Arrow *start_arrow,
1013 Arrow *end_arrow,
1014 real radius)
1016 /* Index of first and last point with a non-zero length segment */
1017 int firstline = 0;
1018 int lastline = num_points;
1019 Point oldstart = points[firstline];
1020 Point oldend = points[lastline-1];
1021 Point start_arrow_head;
1022 Point end_arrow_head;
1024 if (start_arrow != NULL && start_arrow->type != ARROW_NONE) {
1025 Point move_arrow, move_line;
1026 while (firstline < num_points-1 &&
1027 distance_point_point(&points[firstline],
1028 &points[firstline+1]) < 0.0000001)
1029 firstline++;
1030 if (firstline == num_points-1)
1031 firstline = 0; /* No non-zero lines, it doesn't matter. */
1032 oldstart = points[firstline];
1033 calculate_arrow_point(start_arrow,
1034 &points[firstline], &points[firstline+1],
1035 &move_arrow, &move_line,
1036 line_width);
1037 start_arrow_head = points[firstline];
1038 point_sub(&start_arrow_head, &move_arrow);
1039 point_sub(&points[firstline], &move_line);
1041 if (end_arrow != NULL && end_arrow->type != ARROW_NONE) {
1042 Point move_arrow, move_line;
1043 while (lastline > 0 &&
1044 distance_point_point(&points[lastline-1],
1045 &points[lastline-2]) < 0.0000001)
1046 lastline--;
1047 if (lastline == 0)
1048 firstline = num_points; /* No non-zero lines, it doesn't matter. */
1049 oldend = points[lastline-1];
1050 calculate_arrow_point(end_arrow, &points[lastline-1],
1051 &points[lastline-2],
1052 &move_arrow, &move_line,
1053 line_width);
1054 end_arrow_head = points[lastline-1];
1055 point_sub(&end_arrow_head, &move_arrow);
1056 point_sub(&points[lastline-1], &move_line);
1058 /* Don't draw degenerate line segments at end of line */
1059 if (lastline-firstline > 1) /* only if there is something */
1060 DIA_RENDERER_GET_CLASS(renderer)->draw_rounded_polyline(renderer,
1061 &points[firstline],
1062 lastline-firstline,
1063 color, radius);
1064 if (start_arrow != NULL && start_arrow->type != ARROW_NONE)
1065 arrow_draw(renderer, start_arrow->type,
1066 &start_arrow_head, &points[firstline+1],
1067 start_arrow->length, start_arrow->width,
1068 line_width,
1069 color, &color_white);
1070 if (end_arrow != NULL && end_arrow->type != ARROW_NONE)
1071 arrow_draw(renderer, end_arrow->type,
1072 &end_arrow_head, &points[lastline-2],
1073 end_arrow->length, end_arrow->width,
1074 line_width,
1075 color, &color_white);
1077 points[firstline] = oldstart;
1078 points[lastline-1] = oldend;
1081 /** Figure the equation for a line given by two points.
1082 * Returns FALSE if the line is vertical (infinite a).
1084 static gboolean
1085 points_to_line(real *a, real *b, Point *p1, Point *p2)
1087 if (fabs(p1->x - p2->x) < 0.000000001)
1088 return FALSE;
1089 *a = (p2->y-p1->y)/(p2->x-p1->x);
1090 *b = p1->y-(*a)*p1->x;
1091 return TRUE;
1094 /** Find the intersection between two lines.
1095 * Returns TRUE if the lines intersect in a single point.
1097 static gboolean
1098 intersection_line_line(Point *cross,
1099 Point *p1a, Point *p1b,
1100 Point *p2a, Point *p2b)
1102 real a1, b1, a2, b2;
1104 /* Find coefficients of lines */
1105 if (!(points_to_line(&a1, &b1, p1a, p1b))) {
1106 if (!(points_to_line(&a2, &b2, p2a, p2b))) {
1107 if (fabs(p1a->x-p2a->x) < 0.00000001) {
1108 *cross = *p1a;
1109 return TRUE;
1110 } else return FALSE;
1112 cross->x = p1a->x;
1113 cross->y = a2*(p1a->x)+b2;
1114 return TRUE;
1116 if (!(points_to_line(&a2, &b2, p2a, p2b))) {
1117 cross->x = p2a->x;
1118 cross->y = a1*(p2a->x)+b1;
1119 return TRUE;
1121 /* Solve */
1122 if (fabs(a1-a2) < 0.000000001) {
1123 if (fabs(b1-b2) < 0.000000001) {
1124 *cross = *p1a;
1125 return TRUE;
1126 } else {
1127 return FALSE;
1129 } else {
1131 a1x+b1 = a2x+b2;
1132 a1x = a2x+b2-b1;
1133 a1x-a2x = b2-b1;
1134 (a1-a2)x = b2-b1;
1135 x = (b2-b1)/(a1-a2)
1137 cross->x = (b2-b1)/(a1-a2);
1138 cross->y = a1*cross->x+b1;
1139 return TRUE;
1143 /** Given three points, find the center of the circle they describe.
1144 * Returns FALSE if the center could not be determined (i.e. the points
1145 * all lie really close together).
1146 * The renderer should disappear once the debugging is done.
1148 static gboolean
1149 find_center_point(Point *center, Point *p1, Point *p2, Point *p3)
1151 Point mid1;
1152 Point mid2;
1153 Point orth1;
1154 Point orth2;
1155 real tmp;
1157 /* Find vector from middle between two points towards center */
1158 mid1 = *p1;
1159 point_sub(&mid1, p2);
1160 point_scale(&mid1, 0.5);
1161 orth1 = mid1;
1162 point_add(&mid1, p2); /* Now midpoint between p1 & p2 */
1163 tmp = orth1.x;
1164 orth1.x = orth1.y;
1165 orth1.y = -tmp;
1166 point_add(&orth1, &mid1);
1169 /* Again, with two other points */
1170 mid2 = *p2;
1171 point_sub(&mid2, p3);
1172 point_scale(&mid2, 0.5);
1173 orth2 = mid2;
1174 point_add(&mid2, p3); /* Now midpoint between p2 & p3 */
1175 tmp = orth2.x;
1176 orth2.x = orth2.y;
1177 orth2.y = -tmp;
1178 point_add(&orth2, &mid2);
1180 /* The intersection between these two is the center */
1181 if (!intersection_line_line(center, &mid1, &orth1, &mid2, &orth2)) {
1182 /* Degenerate circle */
1183 /* Case 1: Points are all on top of each other. Nothing to do. */
1184 if (fabs((p1->x + p2->x + p3->x)/3 - p1->x) < 0.0000001 &&
1185 fabs((p1->y + p2->y + p3->y)/3 - p1->y) < 0.0000001) {
1186 return FALSE;
1189 /* Case 2: Two points are on top of each other. Midpoint of
1190 * non-degenerate line is center. */
1191 if (distance_point_point_manhattan(p1, p2) < 0.0000001) {
1192 *center = mid2;
1193 return TRUE;
1194 } else if (distance_point_point_manhattan(p1, p3) < 0.0000001 ||
1195 distance_point_point_manhattan(p2, p3) < 0.0000001) {
1196 *center = mid1;
1197 return TRUE;
1199 /* Case 3: All points on a line. Nothing to do. */
1200 return FALSE;
1202 return TRUE;
1205 static gboolean
1206 is_right_hand (const Point *a, const Point *b, const Point *c)
1208 Point dot1, dot2;
1210 dot1 = *a;
1211 point_sub(&dot1, c);
1212 point_normalize(&dot1);
1213 dot2 = *b;
1214 point_sub(&dot2, c);
1215 point_normalize(&dot2);
1216 return point_cross(&dot1, &dot2) > 0;
1219 static void
1220 draw_arc_with_arrows (DiaRenderer *renderer,
1221 Point *startpoint,
1222 Point *endpoint,
1223 Point *midpoint,
1224 real line_width,
1225 Color *color,
1226 Arrow *start_arrow,
1227 Arrow *end_arrow)
1229 Point oldstart = *startpoint;
1230 Point oldend = *endpoint;
1231 Point center;
1232 real width, angle1, angle2, arrow_ofs = 0.0;
1233 gboolean righthand;
1234 Point start_arrow_head;
1235 Point start_arrow_end;
1236 Point end_arrow_head;
1237 Point end_arrow_end;
1239 if (!find_center_point(&center, startpoint, endpoint, midpoint)) {
1240 /* Degenerate circle -- should have been caught by the drawer? */
1241 printf("Degenerate\n");
1244 righthand = is_right_hand (startpoint, midpoint, endpoint);
1246 width = 2*distance_point_point(&center, startpoint);
1248 if (start_arrow != NULL && start_arrow->type != ARROW_NONE) {
1249 Point move_arrow, move_line;
1250 real tmp;
1252 start_arrow_end = *startpoint;
1253 point_sub(&start_arrow_end, &center);
1254 tmp = start_arrow_end.x;
1255 if (righthand) {
1256 start_arrow_end.x = -start_arrow_end.y;
1257 start_arrow_end.y = tmp;
1258 } else {
1259 start_arrow_end.x = start_arrow_end.y;
1260 start_arrow_end.y = -tmp;
1262 point_add(&start_arrow_end, startpoint);
1264 calculate_arrow_point(start_arrow, startpoint, &start_arrow_end,
1265 &move_arrow, &move_line,
1266 line_width);
1267 start_arrow_head = *startpoint;
1268 point_sub(&start_arrow_head, &move_arrow);
1269 point_sub(startpoint, &move_line);
1270 arrow_ofs += sqrt (move_line.x * move_line.x + move_line.y * move_line.y);
1272 if (end_arrow != NULL && end_arrow->type != ARROW_NONE) {
1273 Point move_arrow, move_line;
1274 real tmp;
1276 end_arrow_end = *endpoint;
1277 point_sub(&end_arrow_end, &center);
1278 tmp = end_arrow_end.x;
1279 if (righthand) {
1280 end_arrow_end.x = end_arrow_end.y;
1281 end_arrow_end.y = -tmp;
1282 } else {
1283 end_arrow_end.x = -end_arrow_end.y;
1284 end_arrow_end.y = tmp;
1286 point_add(&end_arrow_end, endpoint);
1288 calculate_arrow_point(end_arrow, endpoint, &end_arrow_end,
1289 &move_arrow, &move_line,
1290 line_width);
1291 end_arrow_head = *endpoint;
1292 point_sub(&end_arrow_head, &move_arrow);
1293 point_sub(endpoint, &move_line);
1294 arrow_ofs += sqrt (move_line.x * move_line.x + move_line.y * move_line.y);
1297 /* Now we possibly have new start- and endpoint. We must not
1298 * recalculate the center cause the new points lie on the tangential
1299 * approximation of the original arc arrow lines not on the arc itself.
1300 * The one thing we need to deal with is calculating the (new) angles
1301 * and get rid of the arc drawing altogether if got degenerated.
1303 * Why shouldn't we recalculate the whole thing from the new start/endpoints?
1304 * Done this way the arc does not come out the back of the arrows.
1305 * -LC, 20/2/2006
1307 angle1 = -atan2(startpoint->y - center.y, startpoint->x - center.x)*180.0/G_PI;
1308 while (angle1 < 0.0) angle1 += 360.0;
1309 angle2 = -atan2(endpoint->y - center.y, endpoint->x - center.x)*180.0/G_PI;
1310 while (angle2 < 0.0) angle2 += 360.0;
1311 if (righthand) {
1312 real tmp = angle1;
1313 angle1 = angle2;
1314 angle2 = tmp;
1316 /* now with the angles we can bring the startpoint back to the arc, but there must be a less expensive way to do this? */
1317 if (start_arrow != NULL && start_arrow->type != ARROW_NONE) {
1318 startpoint->x = cos (G_PI * angle1 / 180.0) * width / 2.0 + center.x;
1319 startpoint->y = sin (G_PI * angle1 / 180.0) * width / 2.0 + center.y;
1321 if (end_arrow != NULL && end_arrow->type != ARROW_NONE) {
1322 endpoint->x = cos (G_PI * angle1 / 180.0) * width / 2.0 + center.x;
1323 endpoint->y = sin (G_PI * angle1 / 180.0) * width / 2.0 + center.y;
1326 DIA_RENDERER_GET_CLASS(renderer)->draw_arc(renderer, &center, width, width,
1327 angle1, angle2, color);
1329 if (start_arrow != NULL && start_arrow->type != ARROW_NONE)
1330 arrow_draw(renderer, start_arrow->type,
1331 &start_arrow_head, &start_arrow_end,
1332 start_arrow->length, start_arrow->width,
1333 line_width,
1334 color, &color_white);
1335 if (end_arrow != NULL && end_arrow->type != ARROW_NONE)
1336 arrow_draw(renderer, end_arrow->type,
1337 &end_arrow_head, &end_arrow_end,
1338 end_arrow->length, end_arrow->width,
1339 line_width,
1340 color, &color_white);
1342 *startpoint = oldstart;
1343 *endpoint = oldend;
1346 static void
1347 draw_bezier_with_arrows(DiaRenderer *renderer,
1348 BezPoint *points,
1349 int num_points,
1350 real line_width,
1351 Color *color,
1352 Arrow *start_arrow,
1353 Arrow *end_arrow)
1355 Point startpoint, endpoint;
1356 Point start_arrow_head;
1357 Point end_arrow_head;
1359 startpoint = points[0].p1;
1360 endpoint = points[num_points-1].p3;
1362 if (start_arrow != NULL && start_arrow->type != ARROW_NONE) {
1363 Point move_arrow;
1364 Point move_line;
1365 calculate_arrow_point(start_arrow, &points[0].p1, &points[1].p1,
1366 &move_arrow, &move_line,
1367 line_width);
1368 start_arrow_head = points[0].p1;
1369 point_sub(&start_arrow_head, &move_arrow);
1370 point_sub(&points[0].p1, &move_line);
1372 if (end_arrow != NULL && end_arrow->type != ARROW_NONE) {
1373 Point move_arrow;
1374 Point move_line;
1375 calculate_arrow_point(end_arrow,
1376 &points[num_points-1].p3, &points[num_points-1].p2,
1377 &move_arrow, &move_line,
1378 line_width);
1379 end_arrow_head = points[num_points-1].p3;
1380 point_sub(&end_arrow_head, &move_arrow);
1381 point_sub(&points[num_points-1].p3, &move_line);
1383 DIA_RENDERER_GET_CLASS(renderer)->draw_bezier(renderer, points, num_points, color);
1384 if (start_arrow != NULL && start_arrow->type != ARROW_NONE)
1385 arrow_draw(renderer, start_arrow->type,
1386 &start_arrow_head, &points[1].p1,
1387 start_arrow->length, start_arrow->width,
1388 line_width,
1389 color, &color_white);
1390 if (end_arrow != NULL && end_arrow->type != ARROW_NONE)
1391 arrow_draw(renderer, end_arrow->type,
1392 &end_arrow_head, &points[num_points-1].p2,
1393 end_arrow->length, end_arrow->width,
1394 line_width,
1395 color, &color_white);
1397 points[0].p1 = startpoint;
1398 points[num_points-1].p3 = endpoint;
1403 * Should we really provide this ? It formerly was an 'interactive op'
1404 * and depends on DiaRenderer::set_font() not or properly overwritten
1406 static real
1407 get_text_width (DiaRenderer *renderer,
1408 const gchar *text, int length)
1410 real ret = 0;
1412 if (renderer->font) {
1413 char *str = g_strndup (text, length);
1415 ret = dia_font_string_width (str,
1416 renderer->font,
1417 renderer->font_height);
1418 g_free (str);
1421 return ret;
1424 static int
1425 get_width_pixels (DiaRenderer *renderer)
1427 g_return_val_if_fail (renderer->is_interactive, 0);
1428 return 0;
1431 static int
1432 get_height_pixels (DiaRenderer *renderer)
1434 g_return_val_if_fail (renderer->is_interactive, 0);
1435 return 0;
1440 * non member functions
1443 dia_renderer_get_width_pixels (DiaRenderer *renderer)
1445 return DIA_RENDERER_GET_CLASS(renderer)->get_width_pixels (renderer);
1449 dia_renderer_get_height_pixels (DiaRenderer *renderer)
1451 return DIA_RENDERER_GET_CLASS(renderer)->get_height_pixels (renderer);