1 /* Python plug-in for dia
2 * Copyright (C) 1999 James Henstridge
3 * Copyright (C) 2000,2002 Hans Breuer
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include <config.h>
21
22 #include <Python.h>
23 #include <glib.h>
24 #include <glib/gstdio.h>
25
26 #include <locale.h>
27
28 #include "intl.h"
29 #include "message.h"
30 #include "geometry.h"
31
32 #include "pydia-object.h" /* for PyObject_HEAD_INIT */
33 #include "pydia-export.h"
34 #include "pydia-diagramdata.h"
35 #include "pydia-geometry.h"
36 #include "pydia-color.h"
37 #include "pydia-font.h"
38 #include "pydia-image.h"
39 #include "pydia-error.h"
40
41 /*
42 * The PyDiaRenderer is currently defined in Python only. The
43 * DiaPyRenderer is using it's interface to map the gobject
44 * DiaRenderer to it. A next step could be to let Python code
45 * directly inherit from DiaPyRenderer.
46 * To do that probably some code from pygtk.gobject needs to
47 * be borrowed/shared
48 */
49 #include "diarenderer.h"
50
51 #define DIA_TYPE_PY_RENDERER (dia_py_renderer_get_type ())
52 #define DIA_PY_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DIA_TYPE_PY_RENDERER, DiaPyRenderer))
53 #define DIA_PY_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), DIA_TYPE_PY_RENDERER, DiaPyRendererClass))
54 #define DIA_IS_PY_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), DIA_TYPE_PY_RENDERER))
55 #define DIA_PY_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), DIA_TYPE_PY_RENDERER, DiaPyRendererClass))
56
57 GType dia_py_renderer_get_type (void) G_GNUC_CONST;
58
59 typedef struct _DiaPyRenderer DiaPyRenderer;
60 typedef struct _DiaPyRendererClass DiaPyRendererClass;
61
62 struct _DiaPyRenderer
63 {
64 DiaRenderer parent_instance;
65
66 char* filename;
67 PyObject* self;
68 PyObject* diagram_data;
69 char* old_locale;
70 };
71
72 struct _DiaPyRendererClass
73 {
74 DiaRendererClass parent_class;
75 };
76
77 #define PYDIA_RENDERER(renderer) \
78 (DIA_PY_RENDERER(renderer)->self)
79
80 /*
81 * Members overwritable by Python scripts
82 */
83 static void
begin_render(DiaRenderer * renderer)84 begin_render(DiaRenderer *renderer)
85 {
86 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
87
88 DIA_PY_RENDERER(renderer)->old_locale = setlocale(LC_NUMERIC, "C");
89
90 func = PyObject_GetAttrString (self, "begin_render");
91 if (func && PyCallable_Check(func)) {
92 Py_INCREF(self);
93 Py_INCREF(func);
94 arg = Py_BuildValue ("(Os)",
95 DIA_PY_RENDERER(renderer)->diagram_data,
96 DIA_PY_RENDERER(renderer)->filename);
97 if (arg) {
98 res = PyEval_CallObject (func, arg);
99 ON_RES(res, FALSE);
100 }
101 Py_XDECREF (arg);
102 Py_DECREF (func);
103 Py_DECREF (self);
104 }
105 }
106
107 static void
end_render(DiaRenderer * renderer)108 end_render(DiaRenderer *renderer)
109 {
110 PyObject *func, *res, *self = PYDIA_RENDERER (renderer);
111
112 func = PyObject_GetAttrString (self, "end_render");
113 if (func && PyCallable_Check(func)) {
114 Py_INCREF(self);
115 Py_INCREF(func);
116 res = PyEval_CallObject (func, (PyObject *)NULL);
117 ON_RES(res, FALSE);
118 Py_DECREF(func);
119 Py_DECREF(self);
120 }
121
122 Py_DECREF (DIA_PY_RENDERER(renderer)->diagram_data);
123 g_free (DIA_PY_RENDERER(renderer)->filename);
124 DIA_PY_RENDERER(renderer)->filename = NULL;
125
126 setlocale(LC_NUMERIC, DIA_PY_RENDERER(renderer)->old_locale);
127 }
128
129 static void
set_linewidth(DiaRenderer * renderer,real linewidth)130 set_linewidth(DiaRenderer *renderer, real linewidth)
131 {
132 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
133
134 func = PyObject_GetAttrString (self, "set_linewidth");
135 if (func && PyCallable_Check(func)) {
136 Py_INCREF(self);
137 Py_INCREF(func);
138 arg = Py_BuildValue ("(d)", linewidth);
139 if (arg) {
140 res = PyEval_CallObject (func, arg);
141 ON_RES(res, FALSE);
142 }
143 Py_XDECREF (arg);
144 Py_DECREF(func);
145 Py_DECREF(self);
146 }
147 else /* member optional */
148 PyErr_Clear();
149 }
150
151 static void
set_linecaps(DiaRenderer * renderer,LineCaps mode)152 set_linecaps(DiaRenderer *renderer, LineCaps mode)
153 {
154 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
155
156 switch(mode) {
157 case LINECAPS_BUTT:
158 break;
159 case LINECAPS_ROUND:
160 break;
161 case LINECAPS_PROJECTING:
162 break;
163 default:
164 PyErr_Warn (PyExc_RuntimeWarning, "DiaPyRenderer : Unsupported fill mode specified!\n");
165 }
166
167 func = PyObject_GetAttrString (self, "set_linecaps");
168 if (func && PyCallable_Check(func)) {
169 Py_INCREF(self);
170 Py_INCREF(func);
171 arg = Py_BuildValue ("(i)", mode);
172 if (arg) {
173 res = PyEval_CallObject (func, arg);
174 ON_RES(res, FALSE);
175 }
176 Py_XDECREF (arg);
177 Py_DECREF(func);
178 Py_DECREF(self);
179 }
180 else /* member optional */
181 PyErr_Clear();
182 }
183
184 static void
set_linejoin(DiaRenderer * renderer,LineJoin mode)185 set_linejoin(DiaRenderer *renderer, LineJoin mode)
186 {
187 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
188
189 switch(mode) {
190 case LINEJOIN_MITER:
191 break;
192 case LINEJOIN_ROUND:
193 break;
194 case LINEJOIN_BEVEL:
195 break;
196 default:
197 PyErr_Warn (PyExc_RuntimeWarning, "DiaPyRenderer : Unsupported fill mode specified!\n");
198 }
199
200 func = PyObject_GetAttrString (self, "set_linejoin");
201 if (func && PyCallable_Check(func)) {
202 Py_INCREF(self);
203 Py_INCREF(func);
204 arg = Py_BuildValue ("(i)", mode);
205 if (arg) {
206 res = PyEval_CallObject (func, arg);
207 ON_RES(res, FALSE);
208 }
209 Py_XDECREF (arg);
210 Py_DECREF(func);
211 Py_DECREF(self);
212 }
213 else /* member optional */
214 PyErr_Clear();
215 }
216
217 static void
set_linestyle(DiaRenderer * renderer,LineStyle mode)218 set_linestyle(DiaRenderer *renderer, LineStyle mode)
219 {
220 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
221
222 /* line type */
223 switch (mode) {
224 case LINESTYLE_SOLID:
225 break;
226 case LINESTYLE_DASHED:
227 break;
228 case LINESTYLE_DASH_DOT:
229 break;
230 case LINESTYLE_DASH_DOT_DOT:
231 break;
232 case LINESTYLE_DOTTED:
233 break;
234 default:
235 PyErr_Warn (PyExc_RuntimeWarning, "DiaPyRenderer : Unsupported fill mode specified!\n");
236 }
237
238 func = PyObject_GetAttrString (self, "set_linestyle");
239 if (func && PyCallable_Check(func)) {
240 Py_INCREF(self);
241 Py_INCREF(func);
242 arg = Py_BuildValue ("(i)", mode);
243 if (arg) {
244 res = PyEval_CallObject (func, arg);
245 ON_RES(res, FALSE);
246 }
247 Py_XDECREF (arg);
248 Py_DECREF(func);
249 Py_DECREF(self);
250 }
251 else /* member optional */
252 PyErr_Clear();
253 }
254
255 static void
set_dashlength(DiaRenderer * renderer,real length)256 set_dashlength(DiaRenderer *renderer, real length)
257 {
258 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
259
260 func = PyObject_GetAttrString (self, "set_dashlength");
261 if (func && PyCallable_Check(func)) {
262 Py_INCREF(self);
263 Py_INCREF(func);
264 arg = Py_BuildValue ("(d)", length);
265 if (arg) {
266 res = PyEval_CallObject (func, arg);
267 ON_RES(res, FALSE);
268 }
269 Py_XDECREF (arg);
270 Py_DECREF(func);
271 Py_DECREF(self);
272 }
273 else /* member optional */
274 PyErr_Clear();
275 }
276
277 static void
set_fillstyle(DiaRenderer * renderer,FillStyle mode)278 set_fillstyle(DiaRenderer *renderer, FillStyle mode)
279 {
280 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
281
282 switch(mode) {
283 case FILLSTYLE_SOLID:
284 break;
285 default:
286 PyErr_Warn (PyExc_RuntimeWarning, "DiaPyRenderer : Unsupported fill mode specified!\n");
287 }
288
289 func = PyObject_GetAttrString (self, "set_fillstyle");
290 if (func && PyCallable_Check(func)) {
291 Py_INCREF(self);
292 Py_INCREF(func);
293 arg = Py_BuildValue ("(i)", mode);
294 if (arg) {
295 res = PyEval_CallObject (func, arg);
296 ON_RES(res, FALSE);
297 }
298 Py_XDECREF (arg);
299 Py_DECREF(func);
300 Py_DECREF(self);
301 }
302 else /* member optional */
303 PyErr_Clear();
304 }
305
306 static void
set_font(DiaRenderer * renderer,DiaFont * font,real height)307 set_font(DiaRenderer *renderer, DiaFont *font, real height)
308 {
309 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
310
311 func = PyObject_GetAttrString (self, "set_font");
312 if (func && PyCallable_Check(func)) {
313 Py_INCREF(self);
314 Py_INCREF(func);
315 arg = Py_BuildValue ("(Od)", PyDiaFont_New (font), height);
316 if (arg) {
317 res = PyEval_CallObject (func, arg);
318 ON_RES(res, FALSE);
319 }
320 Py_XDECREF (arg);
321 Py_DECREF(func);
322 Py_DECREF(self);
323 }
324 else /* member optional */
325 PyErr_Clear();
326 }
327
328 static gpointer parent_class = NULL;
329
330 static void
draw_line(DiaRenderer * renderer,Point * start,Point * end,Color * line_colour)331 draw_line(DiaRenderer *renderer,
332 Point *start, Point *end,
333 Color *line_colour)
334 {
335 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
336
337 func = PyObject_GetAttrString (self, "draw_line");
338 if (func && PyCallable_Check(func)) {
339 Py_INCREF(self);
340 Py_INCREF(func);
341 arg = Py_BuildValue ("(OOO)", PyDiaPoint_New (start),
342 PyDiaPoint_New (end),
343 PyDiaColor_New (line_colour));
344 if (arg) {
345 res = PyEval_CallObject (func, arg);
346 ON_RES(res, FALSE);
347 }
348 Py_XDECREF (arg);
349 Py_DECREF(func);
350 Py_DECREF(self);
351 }
352 else { /* member not optional */
353 gchar *msg = g_strdup_printf ("%s.draw_line() implmentation missing.",
354 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
355 PyErr_Clear();
356 PyErr_Warn (PyExc_RuntimeWarning, msg);
357 g_free (msg);
358 }
359 }
360
361 static void
draw_polyline(DiaRenderer * renderer,Point * points,int num_points,Color * line_colour)362 draw_polyline(DiaRenderer *renderer,
363 Point *points, int num_points,
364 Color *line_colour)
365 {
366 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
367
368 func = PyObject_GetAttrString (self, "draw_polyline");
369 if (func && PyCallable_Check(func)) {
370 Py_INCREF(self);
371 Py_INCREF(func);
372 arg = Py_BuildValue ("(OO)", PyDiaPointTuple_New (points, num_points),
373 PyDiaColor_New (line_colour));
374 if (arg) {
375 res = PyEval_CallObject (func, arg);
376 ON_RES(res, FALSE);
377 }
378 Py_XDECREF (arg);
379 Py_DECREF(func);
380 Py_DECREF(self);
381 }
382 else { /* member optional */
383 PyErr_Clear();
384 /* XXX: implementing the same fallback as DiaRenderer */
385 DIA_RENDERER_CLASS (parent_class)->draw_polyline (renderer, points, num_points, line_colour);
386 }
387 }
388
389 static void
draw_polygon(DiaRenderer * renderer,Point * points,int num_points,Color * line_colour)390 draw_polygon(DiaRenderer *renderer,
391 Point *points, int num_points,
392 Color *line_colour)
393 {
394 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
395
396 func = PyObject_GetAttrString (self, "draw_polygon");
397 if (func && PyCallable_Check(func)) {
398 Py_INCREF(self);
399 Py_INCREF(func);
400 arg = Py_BuildValue ("(OO)", PyDiaPointTuple_New (points, num_points),
401 PyDiaColor_New (line_colour));
402 if (arg) {
403 res = PyEval_CallObject (func, arg);
404 ON_RES(res, FALSE);
405 }
406 Py_XDECREF (arg);
407 Py_DECREF(func);
408 Py_DECREF(self);
409 }
410 else { /* member optional */
411 PyErr_Clear();
412 /* XXX: implementing the same fallback as DiaRenderer would do */
413 DIA_RENDERER_CLASS (parent_class)->draw_polygon (renderer, points, num_points, line_colour);
414 }
415 }
416
417 static void
fill_polygon(DiaRenderer * renderer,Point * points,int num_points,Color * colour)418 fill_polygon(DiaRenderer *renderer,
419 Point *points, int num_points,
420 Color *colour)
421 {
422 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
423
424 func = PyObject_GetAttrString (self, "fill_polygon");
425 if (func && PyCallable_Check(func)) {
426 Py_INCREF(self);
427 Py_INCREF(func);
428 arg = Py_BuildValue ("(OO)", PyDiaPointTuple_New (points, num_points),
429 PyDiaColor_New (colour));
430 if (arg) {
431 res = PyEval_CallObject (func, arg);
432 ON_RES(res, FALSE);
433 }
434 Py_XDECREF (arg);
435 Py_DECREF(func);
436 Py_DECREF(self);
437 }
438 else { /* member not optional */
439 gchar *msg = g_strdup_printf ("%s.fill_polygon() implmentation missing.",
440 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
441 PyErr_Clear();
442 PyErr_Warn (PyExc_RuntimeWarning, msg);
443 g_free (msg);
444 }
445 }
446
447 static void
draw_rect(DiaRenderer * renderer,Point * ul_corner,Point * lr_corner,Color * colour)448 draw_rect(DiaRenderer *renderer,
449 Point *ul_corner, Point *lr_corner,
450 Color *colour)
451 {
452 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
453
454 func = PyObject_GetAttrString (self, "draw_rect");
455 if (func && PyCallable_Check(func)) {
456 Py_INCREF(self);
457 Py_INCREF(func);
458 arg = Py_BuildValue ("(OO)", PyDiaRectangle_New_FromPoints (ul_corner, lr_corner),
459 PyDiaColor_New (colour));
460 if (arg) {
461 res = PyEval_CallObject (func, arg);
462 ON_RES(res, FALSE);
463 }
464 Py_XDECREF (arg);
465 Py_DECREF(func);
466 Py_DECREF(self);
467 }
468 else { /* member optional */
469 PyErr_Clear();
470 /* XXX: implementing the same fallback as DiaRenderer would do */
471 DIA_RENDERER_CLASS (parent_class)->draw_rect (renderer, ul_corner, lr_corner, colour);
472 }
473 }
474
475 static void
fill_rect(DiaRenderer * renderer,Point * ul_corner,Point * lr_corner,Color * colour)476 fill_rect(DiaRenderer *renderer,
477 Point *ul_corner, Point *lr_corner,
478 Color *colour)
479 {
480 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
481
482 func = PyObject_GetAttrString (self, "fill_rect");
483 if (func && PyCallable_Check(func)) {
484 Py_INCREF(self);
485 Py_INCREF(func);
486 arg = Py_BuildValue ("(OO)", PyDiaRectangle_New_FromPoints (ul_corner, lr_corner),
487 PyDiaColor_New (colour));
488 if (arg) {
489 res = PyEval_CallObject (func, arg);
490 ON_RES(res, FALSE);
491 }
492 Py_XDECREF (arg);
493 Py_DECREF(func);
494 Py_DECREF(self);
495 }
496 else { /* member not optional */
497 gchar *msg = g_strdup_printf ("%s.fill_rect() implmentation missing.",
498 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
499 PyErr_Clear();
500 PyErr_Warn (PyExc_RuntimeWarning, msg);
501 g_free (msg);
502 }
503 }
504
505 static void
draw_arc(DiaRenderer * renderer,Point * center,real width,real height,real angle1,real angle2,Color * colour)506 draw_arc(DiaRenderer *renderer,
507 Point *center,
508 real width, real height,
509 real angle1, real angle2,
510 Color *colour)
511 {
512 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
513
514 func = PyObject_GetAttrString (self, "draw_arc");
515 if (func && PyCallable_Check(func)) {
516 Py_INCREF(self);
517 Py_INCREF(func);
518 arg = Py_BuildValue ("(OddddO)", PyDiaPoint_New (center),
519 width, height, angle1, angle2,
520 PyDiaColor_New (colour));
521 if (arg) {
522 res = PyEval_CallObject (func, arg);
523 ON_RES(res, FALSE);
524 }
525 Py_XDECREF (arg);
526 Py_DECREF(func);
527 Py_DECREF(self);
528 }
529 else { /* member not optional */
530 gchar *msg = g_strdup_printf ("%s.draw_arc() implmentation missing.",
531 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
532 PyErr_Clear();
533 PyErr_Warn (PyExc_RuntimeWarning, msg);
534 g_free (msg);
535 }
536 }
537
538 static void
fill_arc(DiaRenderer * renderer,Point * center,real width,real height,real angle1,real angle2,Color * colour)539 fill_arc(DiaRenderer *renderer,
540 Point *center,
541 real width, real height,
542 real angle1, real angle2,
543 Color *colour)
544 {
545 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
546
547 func = PyObject_GetAttrString (self, "fill_arc");
548 if (func && PyCallable_Check(func)) {
549 Py_INCREF(self);
550 Py_INCREF(func);
551 arg = Py_BuildValue ("(OddddO)", PyDiaPoint_New (center),
552 width, height, angle1, angle2,
553 PyDiaColor_New (colour));
554 if (arg) {
555 res = PyEval_CallObject (func, arg);
556 ON_RES(res, FALSE);
557 }
558 Py_XDECREF (arg);
559 Py_DECREF(func);
560 Py_DECREF(self);
561 }
562 else { /* member not optional */
563 gchar *msg = g_strdup_printf ("%s.fill_arc() implmentation missing.",
564 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
565 PyErr_Clear();
566 PyErr_Warn (PyExc_RuntimeWarning, msg);
567 g_free (msg);
568 }
569 }
570
571 static void
draw_ellipse(DiaRenderer * renderer,Point * center,real width,real height,Color * colour)572 draw_ellipse(DiaRenderer *renderer,
573 Point *center,
574 real width, real height,
575 Color *colour)
576 {
577 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
578
579 func = PyObject_GetAttrString (self, "draw_ellipse");
580 if (func && PyCallable_Check(func)) {
581 Py_INCREF(self);
582 Py_INCREF(func);
583 arg = Py_BuildValue ("(OddO)", PyDiaPoint_New (center),
584 width, height,
585 PyDiaColor_New (colour));
586 if (arg) {
587 res = PyEval_CallObject (func, arg);
588 ON_RES(res, FALSE);
589 }
590 Py_XDECREF (arg);
591 Py_DECREF(func);
592 Py_DECREF(self);
593 }
594 else { /* member not optional */
595 gchar *msg = g_strdup_printf ("%s.draw_ellipse() implmentation missing.",
596 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
597 PyErr_Clear();
598 PyErr_Warn (PyExc_RuntimeWarning, msg);
599 g_free (msg);
600 }
601 }
602
603 static void
fill_ellipse(DiaRenderer * renderer,Point * center,real width,real height,Color * colour)604 fill_ellipse(DiaRenderer *renderer,
605 Point *center,
606 real width, real height,
607 Color *colour)
608 {
609 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
610
611 func = PyObject_GetAttrString (self, "fill_ellipse");
612 if (func && PyCallable_Check(func)) {
613 Py_INCREF(self);
614 Py_INCREF(func);
615 arg = Py_BuildValue ("(OddO)", PyDiaPoint_New (center),
616 width, height,
617 PyDiaColor_New (colour));
618 if (arg) {
619 res = PyEval_CallObject (func, arg);
620 ON_RES(res, FALSE);
621 }
622 Py_XDECREF (arg);
623 Py_DECREF(func);
624 Py_DECREF(self);
625 }
626 else { /* member not optional */
627 gchar *msg = g_strdup_printf ("%s.fill_ellipse() implmentation missing.",
628 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
629 PyErr_Clear();
630 PyErr_Warn (PyExc_RuntimeWarning, msg);
631 g_free (msg);
632 }
633 }
634
635 static void
draw_bezier(DiaRenderer * renderer,BezPoint * points,int num_points,Color * colour)636 draw_bezier(DiaRenderer *renderer,
637 BezPoint *points,
638 int num_points,
639 Color *colour)
640 {
641 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
642
643 func = PyObject_GetAttrString (self, "draw_bezier");
644 if (func && PyCallable_Check(func)) {
645 Py_INCREF(self);
646 Py_INCREF(func);
647 arg = Py_BuildValue ("(OO)", PyDiaBezPointTuple_New (points, num_points),
648 PyDiaColor_New (colour));
649 if (arg) {
650 res = PyEval_CallObject (func, arg);
651 ON_RES(res, FALSE);
652 }
653 Py_XDECREF (arg);
654 Py_DECREF(func);
655 Py_DECREF(self);
656 }
657 else { /* member optional */
658 PyErr_Clear();
659 /* XXX: implementing the same fallback as DiaRenderer would do */
660 DIA_RENDERER_CLASS (parent_class)->draw_bezier (renderer, points, num_points, colour);
661 }
662 }
663
664 static void
fill_bezier(DiaRenderer * renderer,BezPoint * points,int num_points,Color * colour)665 fill_bezier(DiaRenderer *renderer,
666 BezPoint *points, /* Last point must be same as first point */
667 int num_points,
668 Color *colour)
669 {
670 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
671
672 func = PyObject_GetAttrString (self, "fill_bezier");
673 if (func && PyCallable_Check(func)) {
674 Py_INCREF(self);
675 Py_INCREF(func);
676 arg = Py_BuildValue ("(OO)", PyDiaBezPointTuple_New (points, num_points),
677 PyDiaColor_New (colour));
678 if (arg) {
679 res = PyEval_CallObject (func, arg);
680 ON_RES(res, FALSE);
681 }
682 Py_XDECREF (arg);
683 Py_DECREF(func);
684 Py_DECREF(self);
685 }
686 else { /* member optional */
687 PyErr_Clear();
688 /* XXX: implementing the same fallback as DiaRenderer would do */
689 DIA_RENDERER_CLASS (parent_class)->fill_bezier (renderer, points, num_points, colour);
690 }
691 }
692
693 static void
draw_string(DiaRenderer * renderer,const char * text,Point * pos,Alignment alignment,Color * colour)694 draw_string(DiaRenderer *renderer,
695 const char *text,
696 Point *pos, Alignment alignment,
697 Color *colour)
698 {
699 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
700 int len;
701
702 switch (alignment) {
703 case ALIGN_LEFT:
704 break;
705 case ALIGN_CENTER:
706 break;
707 case ALIGN_RIGHT:
708 break;
709 }
710 /* work out size of first chunk of text */
711 len = strlen(text);
712
713 func = PyObject_GetAttrString (self, "draw_string");
714 if (func && PyCallable_Check(func)) {
715 Py_INCREF(self);
716 Py_INCREF(func);
717 arg = Py_BuildValue ("(sOiO)", text,
718 PyDiaPoint_New (pos),
719 alignment,
720 PyDiaColor_New (colour));
721 if (arg) {
722 res = PyEval_CallObject (func, arg);
723 ON_RES(res, FALSE);
724 }
725 Py_XDECREF (arg);
726 Py_DECREF(func);
727 Py_DECREF(self);
728 } else { /* member not optional */
729 gchar *msg = g_strdup_printf ("%s.draw_string() implmentation missing.",
730 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
731 PyErr_Clear();
732 PyErr_Warn (PyExc_RuntimeWarning, msg);
733 g_free (msg);
734 }
735 }
736
737 static void
draw_image(DiaRenderer * renderer,Point * point,real width,real height,DiaImage * image)738 draw_image(DiaRenderer *renderer,
739 Point *point,
740 real width, real height,
741 DiaImage *image)
742 {
743 PyObject *func, *res, *arg, *self = PYDIA_RENDERER (renderer);
744
745 func = PyObject_GetAttrString (self, "draw_image");
746 if (func && PyCallable_Check(func)) {
747 Py_INCREF(self);
748 Py_INCREF(func);
749 arg = Py_BuildValue ("(OddO)", PyDiaPoint_New (point),
750 width, height,
751 PyDiaImage_New (image));
752 if (arg) {
753 res = PyEval_CallObject (func, arg);
754 ON_RES(res, FALSE);
755 }
756 Py_XDECREF (arg);
757 Py_DECREF(func);
758 Py_DECREF(self);
759 } else { /* member not optional */
760 gchar *msg = g_strdup_printf ("%s.draw_string() implmentation missing.",
761 G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (renderer)));
762 PyErr_Clear();
763 PyErr_Warn (PyExc_RuntimeWarning, msg);
764 g_free (msg);
765 }
766 }
767
768 void
PyDia_export_data(DiagramData * data,const gchar * filename,const gchar * diafilename,void * user_data)769 PyDia_export_data(DiagramData *data, const gchar *filename,
770 const gchar *diafilename, void* user_data)
771 {
772 DiaPyRenderer *renderer;
773
774 {
775 FILE *file;
776 file = g_fopen(filename, "w"); /* "wb" for binary! */
777
778 if (file == NULL) {
779 message_error(_("Couldn't open '%s' for writing.\n"),
780 dia_message_filename(filename));
781 return;
782 }
783 else
784 fclose (file);
785 }
786
787 renderer = g_object_new (DIA_TYPE_PY_RENDERER, NULL);
788
789 renderer->filename = g_strdup (filename);
790 renderer->diagram_data = PyDiaDiagramData_New(data);
791
792 /* The Python Renderer object was created at PyDia_Register */
793 renderer->self = (PyObject*)user_data;
794
795 /* this will call the required callback functions above */
796 data_render(data, DIA_RENDERER(renderer), NULL, NULL, NULL);
797
798 g_object_unref(renderer);
799 }
800
801 /*
802 * GObject boiler plate
803 */
804 static void dia_py_renderer_class_init (DiaPyRendererClass *klass);
805
806 GType
dia_py_renderer_get_type(void)807 dia_py_renderer_get_type (void)
808 {
809 static GType object_type = 0;
810
811 if (!object_type)
812 {
813 static const GTypeInfo object_info =
814 {
815 sizeof (DiaPyRendererClass),
816 (GBaseInitFunc) NULL,
817 (GBaseFinalizeFunc) NULL,
818 (GClassInitFunc) dia_py_renderer_class_init,
819 NULL, /* class_finalize */
820 NULL, /* class_data */
821 sizeof (DiaPyRenderer),
822 0, /* n_preallocs */
823 NULL /* init */
824 };
825
826 object_type = g_type_register_static (DIA_TYPE_RENDERER,
827 "DiaPyRenderer",
828 &object_info, 0);
829 }
830
831 return object_type;
832 }
833
834 static void
dia_py_renderer_finalize(GObject * object)835 dia_py_renderer_finalize (GObject *object)
836 {
837 DiaPyRenderer *renderer = DIA_PY_RENDERER (object);
838
839 if (renderer->filename)
840 g_free (renderer->filename);
841
842 G_OBJECT_CLASS (parent_class)->finalize (object);
843 }
844
845 static void
dia_py_renderer_class_init(DiaPyRendererClass * klass)846 dia_py_renderer_class_init (DiaPyRendererClass *klass)
847 {
848 GObjectClass *object_class = G_OBJECT_CLASS (klass);
849 DiaRendererClass *renderer_class = DIA_RENDERER_CLASS (klass);
850
851 parent_class = g_type_class_peek_parent (klass);
852
853 object_class->finalize = dia_py_renderer_finalize;
854
855 /* all defined members from above */
856 /* renderer members */
857 renderer_class->begin_render = begin_render;
858 renderer_class->end_render = end_render;
859
860 renderer_class->set_linewidth = set_linewidth;
861 renderer_class->set_linecaps = set_linecaps;
862 renderer_class->set_linejoin = set_linejoin;
863 renderer_class->set_linestyle = set_linestyle;
864 renderer_class->set_dashlength = set_dashlength;
865 renderer_class->set_fillstyle = set_fillstyle;
866
867 renderer_class->set_font = set_font;
868
869 renderer_class->draw_line = draw_line;
870 renderer_class->fill_polygon = fill_polygon;
871 renderer_class->draw_rect = draw_rect;
872 renderer_class->fill_rect = fill_rect;
873 renderer_class->draw_arc = draw_arc;
874 renderer_class->fill_arc = fill_arc;
875 renderer_class->draw_ellipse = draw_ellipse;
876 renderer_class->fill_ellipse = fill_ellipse;
877
878 renderer_class->draw_string = draw_string;
879 renderer_class->draw_image = draw_image;
880
881 /* medium level functions */
882 renderer_class->draw_rect = draw_rect;
883 renderer_class->draw_polyline = draw_polyline;
884 renderer_class->draw_polygon = draw_polygon;
885
886 renderer_class->draw_bezier = draw_bezier;
887 renderer_class->fill_bezier = fill_bezier;
888 }
889
890