1 /* Python plug-in for dia
2 * Copyright (C) 1999 James Henstridge
3 * Copyright (C) 2000 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 "pydia-object.h"
23 #include "pydia-geometry.h"
24
25
26 /* Implements wrappers for Point, Rectangle, IntRectangle, BezPoint */
27
28 /*
29 * New
30 */
PyDiaPoint_New(Point * pt)31 PyObject* PyDiaPoint_New (Point* pt)
32 {
33 PyDiaPoint *self;
34
35 self = PyObject_NEW(PyDiaPoint, &PyDiaPoint_Type);
36 if (!self) return NULL;
37
38 self->pt = *pt;
39
40 return (PyObject *)self;
41 }
42
43 PyObject*
PyDiaPointTuple_New(Point * pts,int num)44 PyDiaPointTuple_New (Point* pts, int num)
45 {
46 PyObject* ret;
47 int i;
48
49 ret = PyTuple_New (num);
50 if (ret) {
51 for (i = 0; i < num; i++)
52 PyTuple_SetItem(ret, i, PyDiaPoint_New(&(pts[i])));
53 }
54
55 return ret;
56 }
57
58 /* one of the parameters needs to be NULL, the other is created */
59 PyObject*
PyDiaRectangle_New(Rectangle * r,IntRectangle * ri)60 PyDiaRectangle_New (Rectangle* r, IntRectangle* ri)
61 {
62 PyDiaRectangle *self;
63
64 self = PyObject_NEW(PyDiaRectangle, &PyDiaRectangle_Type);
65 if (!self) return NULL;
66
67 self->is_int = (ri != NULL);
68 if (self->is_int)
69 self->r.ri = *ri;
70 else
71 self->r.rf = *r;
72
73 return (PyObject *)self;
74 }
75
PyDiaRectangle_New_FromPoints(Point * ul,Point * lr)76 PyObject* PyDiaRectangle_New_FromPoints (Point* ul, Point* lr)
77 {
78 PyDiaRectangle *self;
79
80 self = PyObject_NEW(PyDiaRectangle, &PyDiaRectangle_Type);
81 if (!self) return NULL;
82
83 self->is_int = FALSE;
84 self->r.rf.left = ul->x;
85 self->r.rf.top = ul->y;
86 self->r.rf.right = lr->x;
87 self->r.rf.bottom = lr->y;
88
89 return (PyObject *)self;
90 }
91
92
PyDiaBezPoint_New(BezPoint * bpn)93 PyObject* PyDiaBezPoint_New (BezPoint* bpn)
94 {
95 PyDiaBezPoint *self;
96
97 self = PyObject_NEW(PyDiaBezPoint, &PyDiaBezPoint_Type);
98 if (!self) return NULL;
99
100 self->bpn = *bpn;
101
102 return (PyObject *)self;
103 }
104
105 PyObject*
PyDiaBezPointTuple_New(BezPoint * pts,int num)106 PyDiaBezPointTuple_New (BezPoint* pts, int num)
107 {
108 PyObject* ret;
109 int i;
110
111 ret = PyTuple_New (num);
112 if (ret) {
113 for (i = 0; i < num; i++)
114 PyTuple_SetItem(ret, i, PyDiaBezPoint_New(&(pts[i])));
115 }
116
117 return ret;
118 }
119
PyDiaArrow_New(Arrow * arrow)120 PyObject* PyDiaArrow_New (Arrow* arrow)
121 {
122 PyDiaArrow *self;
123
124 self = PyObject_NEW(PyDiaArrow, &PyDiaArrow_Type);
125 if (!self) return NULL;
126
127 self->arrow = *arrow;
128
129 return (PyObject *)self;
130 }
131
132 /*
133 * Dealloc
134 */
135 static void
PyDiaGeometry_Dealloc(void * self)136 PyDiaGeometry_Dealloc(void *self)
137 {
138 PyObject_DEL(self);
139 }
140
141 /*
142 * Compare ?
143 */
144 static int
PyDiaPoint_Compare(PyDiaPoint * self,PyDiaPoint * other)145 PyDiaPoint_Compare(PyDiaPoint *self,
146 PyDiaPoint *other)
147 {
148 #if 1
149 return memcmp (&self->pt, &other->pt, sizeof(Point));
150 #else /* ? */
151 if (self->pt.x == other->pt.x && self->pt.x == other->pt.x) return 0;
152 #define SQR(pt) (pt.x*pt.y)
153 if (SQR(self->pt) > SQR(other->pt)) return -1;
154 #undef SQR
155 return 1;
156 #endif
157 }
158
159 static int
PyDiaRectangle_Compare(PyDiaRectangle * self,PyDiaRectangle * other)160 PyDiaRectangle_Compare(PyDiaRectangle *self,
161 PyDiaRectangle *other)
162 {
163 /* this is not correct */
164 return memcmp (&self->r, &other->r, sizeof(Rectangle));
165 }
166
167 static int
PyDiaBezPoint_Compare(PyDiaBezPoint * self,PyDiaBezPoint * other)168 PyDiaBezPoint_Compare(PyDiaBezPoint *self,
169 PyDiaBezPoint *other)
170 {
171 return memcmp (&self->bpn, &other->bpn, sizeof(BezPoint));
172 }
173
174 static int
PyDiaArrow_Compare(PyDiaArrow * self,PyDiaArrow * other)175 PyDiaArrow_Compare(PyDiaArrow *self,
176 PyDiaArrow *other)
177 {
178 return memcmp (&self->arrow, &other->arrow, sizeof(Arrow));
179 }
180
181 /*
182 * Hash
183 */
184 static long
PyDiaGeometry_Hash(PyObject * self)185 PyDiaGeometry_Hash(PyObject *self)
186 {
187 return (long)self;
188 }
189
190 /*
191 * GetAttr
192 */
193 static PyObject *
PyDiaPoint_GetAttr(PyDiaPoint * self,gchar * attr)194 PyDiaPoint_GetAttr(PyDiaPoint *self, gchar *attr)
195 {
196 if (!strcmp(attr, "__members__"))
197 return Py_BuildValue("[ss]", "x", "y");
198 else if (!strcmp(attr, "x"))
199 return PyFloat_FromDouble(self->pt.x);
200 else if (!strcmp(attr, "y"))
201 return PyFloat_FromDouble(self->pt.y);
202
203 PyErr_SetString(PyExc_AttributeError, attr);
204 return NULL;
205 }
206
207 static PyObject *
PyDiaRectangle_GetAttr(PyDiaRectangle * self,gchar * attr)208 PyDiaRectangle_GetAttr(PyDiaRectangle *self, gchar *attr)
209 {
210 #define I_OR_F(v) \
211 (self->is_int ? \
212 PyInt_FromLong(self->r.ri. v) : PyFloat_FromDouble(self->r.rf. v))
213
214 if (!strcmp(attr, "__members__"))
215 return Py_BuildValue("[ssss]", "top", "left", "right", "bottom" );
216 else if (!strcmp(attr, "top"))
217 return I_OR_F(top);
218 else if (!strcmp(attr, "left"))
219 return I_OR_F(left);
220 else if (!strcmp(attr, "right"))
221 return I_OR_F(right);
222 else if (!strcmp(attr, "bottom"))
223 return I_OR_F(bottom);
224
225 PyErr_SetString(PyExc_AttributeError, attr);
226 return NULL;
227
228 #undef I_O_F
229 }
230
231 static PyObject *
PyDiaBezPoint_GetAttr(PyDiaBezPoint * self,gchar * attr)232 PyDiaBezPoint_GetAttr(PyDiaBezPoint *self, gchar *attr)
233 {
234 if (!strcmp(attr, "__members__"))
235 return Py_BuildValue("[ssss]", "type", "p1", "p2", "p3");
236 else if (!strcmp(attr, "type"))
237 return PyInt_FromLong(self->bpn.type);
238 else if (!strcmp(attr, "p1"))
239 return PyDiaPoint_New(&(self->bpn.p1));
240 else if (!strcmp(attr, "p2"))
241 return PyDiaPoint_New(&(self->bpn.p2));
242 else if (!strcmp(attr, "p3"))
243 return PyDiaPoint_New(&(self->bpn.p3));
244
245 PyErr_SetString(PyExc_AttributeError, attr);
246 return NULL;
247 }
248
249 static PyObject *
PyDiaArrow_GetAttr(PyDiaArrow * self,gchar * attr)250 PyDiaArrow_GetAttr(PyDiaArrow *self, gchar *attr)
251 {
252 if (!strcmp(attr, "__members__"))
253 return Py_BuildValue("[sss]", "type", "width", "length");
254 else if (!strcmp(attr, "type"))
255 return PyInt_FromLong(self->arrow.type);
256 else if (!strcmp(attr, "width"))
257 return PyFloat_FromDouble(self->arrow.width);
258 else if (!strcmp(attr, "length"))
259 return PyFloat_FromDouble(self->arrow.length);
260
261 PyErr_SetString(PyExc_AttributeError, attr);
262 return NULL;
263 }
264
265 /*
266 * SetAttr
267 */
268
269 /* XXX */
270
271 /*
272 * Repr / _Str
273 */
274 static PyObject *
PyDiaPoint_Str(PyDiaPoint * self)275 PyDiaPoint_Str(PyDiaPoint *self)
276 {
277 PyObject* py_s;
278 #ifndef _DEBUG /* gives crashes with nan */
279 gchar* s = g_strdup_printf ("(%f,%f)",
280 (float)(self->pt.x), (float)(self->pt.y));
281 #else
282 gchar* s = g_strdup_printf ("(%e,%e)",
283 (float)(self->pt.x), (float)(self->pt.y));
284 #endif
285 py_s = PyString_FromString(s);
286 g_free(s);
287 return py_s;
288 }
289
290 static PyObject *
PyDiaRectangle_Str(PyDiaRectangle * self)291 PyDiaRectangle_Str(PyDiaRectangle *self)
292 {
293 PyObject* py_s;
294 gchar* s;
295 if (self->is_int)
296 s = g_strdup_printf ("((%d,%d),(%d,%d))",
297 (self->r.ri.left), (self->r.ri.top),
298 (self->r.ri.right), (self->r.ri.bottom));
299 else
300 #ifndef _DEBUG /* gives crashes with nan */
301 s = g_strdup_printf ("((%f,%f),(%f,%f))",
302 (float)(self->r.rf.left), (float)(self->r.rf.top),
303 (float)(self->r.rf.right), (float)(self->r.rf.bottom));
304 #else
305 s = g_strdup_printf ("((%e,%e),(%e,%e))",
306 (float)(self->r.rf.left), (float)(self->r.rf.top),
307 (float)(self->r.rf.right), (float)(self->r.rf.bottom));
308 #endif
309 py_s = PyString_FromString(s);
310 g_free(s);
311 return py_s;
312 }
313
314 static PyObject *
PyDiaBezPoint_Str(PyDiaBezPoint * self)315 PyDiaBezPoint_Str(PyDiaBezPoint *self)
316 {
317 PyObject* py_s;
318 #if 0 /* FIXME: this is causing bad crashes with unintialized points.
319 * Probably a glib and a Dia problem ... */
320 gchar* s = g_strdup_printf ("((%f,%f),(%f,%f),(%f,%f),%s)",
321 (float)(self->bpn.p1.x), (float)(self->bpn.p1.y),
322 (float)(self->bpn.p2.x), (float)(self->bpn.p2.y),
323 (float)(self->bpn.p3.x), (float)(self->bpn.p3.y),
324 (self->bpn.type == BEZ_MOVE_TO ? "MOVE_TO" :
325 (self->bpn.type == BEZ_LINE_TO ? "LINE_TO" : "CURVE_TO")));
326 #else
327 gchar* s = g_strdup_printf ("%s",
328 (self->bpn.type == BEZ_MOVE_TO ? "MOVE_TO" :
329 (self->bpn.type == BEZ_LINE_TO ? "LINE_TO" : "CURVE_TO")));
330 #endif
331 py_s = PyString_FromString(s);
332 g_free(s);
333 return py_s;
334 }
335
336
337 static PyObject *
PyDiaArrow_Str(PyDiaArrow * self)338 PyDiaArrow_Str(PyDiaArrow *self)
339 {
340 PyObject* py_s;
341 gchar* s = g_strdup_printf ("(%f,%f, %d)",
342 (float)(self->arrow.width),
343 (float)(self->arrow.length),
344 (int)(self->arrow.type));
345 py_s = PyString_FromString(s);
346 g_free(s);
347 return py_s;
348 }
349
350 /*
351 * sequence interface (query only)
352 */
353 /* Point */
354 static int
point_length(PyDiaRectangle * self)355 point_length(PyDiaRectangle *self)
356 {
357 return 2;
358 }
359 static PyObject *
point_item(PyDiaPoint * self,int i)360 point_item(PyDiaPoint* self, int i)
361 {
362 switch (i) {
363 case 0 : return PyDiaPoint_GetAttr(self, "x");
364 case 1 : return PyDiaPoint_GetAttr(self, "y");
365 default :
366 PyErr_SetString(PyExc_IndexError, "PyDiaPoint index out of range");
367 return NULL;
368 }
369 }
370 static PyObject *
point_slice(PyDiaPoint * self,int i,int j)371 point_slice(PyDiaPoint* self, int i, int j)
372 {
373 PyObject *ret;
374
375 /* j maybe negative */
376 if (j <= 0)
377 j = 1 + j;
378 /* j may be rather huge [:] ^= 0:0x7FFFFFFF */
379 if (j > 1)
380 j = 1;
381 ret = PyTuple_New(j - i + 1);
382 if (ret) {
383 int k;
384 for (k = i; k <= j && k < 2; k++)
385 PyTuple_SetItem(ret, k - i, point_item(self, k));
386 }
387 return ret;
388 }
389
390 static PySequenceMethods point_as_sequence = {
391 (inquiry)point_length, /*sq_length*/
392 (binaryfunc)0, /*sq_concat*/
393 (intargfunc)0, /*sq_repeat*/
394 (intargfunc)point_item, /*sq_item*/
395 (intintargfunc)point_slice, /*sq_slice*/
396 0, /*sq_ass_item*/
397 0, /*sq_ass_slice*/
398 (objobjproc)0 /*sq_contains*/
399 };
400
401 /* Rect */
402 static int
rect_length(PyDiaRectangle * self)403 rect_length(PyDiaRectangle *self)
404 {
405 return 4;
406 }
407 static PyObject *
rect_item(PyDiaRectangle * self,int i)408 rect_item(PyDiaRectangle* self, int i)
409 {
410 switch (i) {
411 case 0 : return PyDiaRectangle_GetAttr(self, "left");
412 case 1 : return PyDiaRectangle_GetAttr(self, "top");
413 case 2 : return PyDiaRectangle_GetAttr(self, "right");
414 case 3 : return PyDiaRectangle_GetAttr(self, "bottom");
415 default :
416 PyErr_SetString(PyExc_IndexError, "PyDiaRectangle index out of range");
417 return NULL;
418 }
419 }
420 static PyObject *
rect_slice(PyDiaRectangle * self,int i,int j)421 rect_slice(PyDiaRectangle* self, int i, int j)
422 {
423 PyObject *ret;
424
425 /* j maybe negative */
426 if (j <= 0)
427 j = 3 + j;
428 /* j may be rather huge [:] ^= 0:0x7FFFFFFF */
429 if (j > 3)
430 j = 3;
431 ret = PyTuple_New(j - i + 1);
432 if (ret) {
433 int k;
434 for (k = i; k <= j && k < 4; k++)
435 PyTuple_SetItem(ret, k - i, rect_item(self, k));
436 }
437 return ret;
438 }
439
440 static PySequenceMethods rect_as_sequence = {
441 (inquiry)rect_length, /*sq_length*/
442 (binaryfunc)0, /*sq_concat*/
443 (intargfunc)0, /*sq_repeat*/
444 (intargfunc)rect_item, /*sq_item*/
445 (intintargfunc)rect_slice, /*sq_slice*/
446 0, /*sq_ass_item*/
447 0, /*sq_ass_slice*/
448 (objobjproc)0 /*sq_contains*/
449 };
450
451 /*
452 * Python objetcs
453 */
454 PyTypeObject PyDiaPoint_Type = {
455 PyObject_HEAD_INIT(&PyType_Type)
456 0,
457 "dia.Point",
458 sizeof(PyDiaPoint),
459 0,
460 (destructor)PyDiaGeometry_Dealloc,
461 (printfunc)0,
462 (getattrfunc)PyDiaPoint_GetAttr,
463 (setattrfunc)0,
464 (cmpfunc)PyDiaPoint_Compare,
465 (reprfunc)0,
466 0, /* as_number */
467 &point_as_sequence,
468 0,
469 (hashfunc)PyDiaGeometry_Hash,
470 (ternaryfunc)0,
471 (reprfunc)PyDiaPoint_Str,
472 (getattrofunc)0,
473 (setattrofunc)0,
474 (PyBufferProcs *)0,
475 0L, /* Flags */
476 "The dia.Point does not only provide access trough it's members but also via a sequence interface."
477 };
478
479 PyTypeObject PyDiaRectangle_Type = {
480 PyObject_HEAD_INIT(&PyType_Type)
481 0,
482 "dia.Rectangle",
483 sizeof(PyDiaRectangle),
484 0,
485 (destructor)PyDiaGeometry_Dealloc,
486 (printfunc)0,
487 (getattrfunc)PyDiaRectangle_GetAttr,
488 (setattrfunc)0,
489 (cmpfunc)PyDiaRectangle_Compare,
490 (reprfunc)0,
491 0, /* as_number */
492 &rect_as_sequence,
493 0, /* as_mapping */
494 (hashfunc)PyDiaGeometry_Hash,
495 (ternaryfunc)0,
496 (reprfunc)PyDiaRectangle_Str,
497 (getattrofunc)0,
498 (setattrofunc)0,
499 (PyBufferProcs *)0,
500 0L, /* Flags */
501 "The dia.Rectangle does not only provide access trough it's members but also via a sequence interface."
502 };
503
504 PyTypeObject PyDiaBezPoint_Type = {
505 PyObject_HEAD_INIT(&PyType_Type)
506 0,
507 "dia.BezPoint",
508 sizeof(PyDiaBezPoint),
509 0,
510 (destructor)PyDiaGeometry_Dealloc,
511 (printfunc)0,
512 (getattrfunc)PyDiaBezPoint_GetAttr,
513 (setattrfunc)0,
514 (cmpfunc)PyDiaBezPoint_Compare,
515 (reprfunc)0,
516 0,
517 0,
518 0,
519 (hashfunc)PyDiaGeometry_Hash,
520 (ternaryfunc)0,
521 (reprfunc)PyDiaBezPoint_Str,
522 (getattrofunc)0,
523 (setattrofunc)0,
524 (PyBufferProcs *)0,
525 0L, /* Flags */
526 "A dia.Point, a bezier type and two control points (dia.Point) make a bezier point."
527 };
528
529 PyTypeObject PyDiaArrow_Type = {
530 PyObject_HEAD_INIT(&PyType_Type)
531 0,
532 "dia.Arrow",
533 sizeof(PyDiaArrow),
534 0,
535 (destructor)PyDiaGeometry_Dealloc,
536 (printfunc)0,
537 (getattrfunc)PyDiaArrow_GetAttr,
538 (setattrfunc)0,
539 (cmpfunc)PyDiaArrow_Compare,
540 (reprfunc)0,
541 0,
542 0,
543 0,
544 (hashfunc)PyDiaGeometry_Hash,
545 (ternaryfunc)0,
546 (reprfunc)PyDiaArrow_Str,
547 (getattrofunc)0,
548 (setattrofunc)0,
549 (PyBufferProcs *)0,
550 0L, /* Flags */
551 "Dia's line objects usually ends with an dia.Arrow"
552 };
553