1 /* -*- Mode: C; c-basic-offset: 4 -*-
2 * Gimp-Python - allows the writing of Gimp plugins in Python.
3 * Copyright (C) 2006 Manish Singh <yosh@gimp.org>
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 3 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, see <https://www.gnu.org/licenses/>.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include "pygimp.h"
24
25
26 static PyObject *vectors_bezier_stroke_new(PyGimpVectors *vectors, int stroke);
27
28
29 typedef struct {
30 PyObject_HEAD
31 gint32 vectors_ID;
32 int stroke;
33 } PyGimpVectorsStroke;
34
35 static PyObject *
vs_get_length(PyGimpVectorsStroke * self,PyObject * args,PyObject * kwargs)36 vs_get_length(PyGimpVectorsStroke *self, PyObject *args, PyObject *kwargs)
37 {
38 double precision;
39 double length;
40
41 static char *kwlist[] = { "precision", NULL };
42
43 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d:get_length", kwlist,
44 &precision))
45 return NULL;
46
47 length = gimp_vectors_stroke_get_length(self->vectors_ID, self->stroke,
48 precision);
49
50 return PyFloat_FromDouble(length);
51 }
52
53 static PyObject *
vs_get_point_at_dist(PyGimpVectorsStroke * self,PyObject * args,PyObject * kwargs)54 vs_get_point_at_dist(PyGimpVectorsStroke *self, PyObject *args, PyObject *kwargs)
55 {
56 double dist, precision;
57 double x, y, slope;
58 gboolean valid;
59 PyObject *ret;
60
61 static char *kwlist[] = { "dist", "precision", NULL };
62
63 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
64 "dd:get_point_at_dist", kwlist,
65 &dist, &precision))
66 return NULL;
67
68 gimp_vectors_stroke_get_point_at_dist(self->vectors_ID, self->stroke,
69 dist, precision,
70 &x, &y, &slope, &valid);
71
72 ret = PyTuple_New(4);
73 if (ret == NULL)
74 return NULL;
75
76 PyTuple_SetItem(ret, 0, PyFloat_FromDouble(x));
77 PyTuple_SetItem(ret, 1, PyFloat_FromDouble(y));
78 PyTuple_SetItem(ret, 2, PyFloat_FromDouble(slope));
79 PyTuple_SetItem(ret, 3, PyBool_FromLong(valid));
80
81 return ret;
82 }
83
84 static PyObject *
vs_close(PyGimpVectorsStroke * self)85 vs_close(PyGimpVectorsStroke *self)
86 {
87 gimp_vectors_stroke_close(self->vectors_ID, self->stroke);
88 Py_INCREF(Py_None);
89 return Py_None;
90 }
91
92
93 static PyObject *
vs_translate(PyGimpVectorsStroke * self,PyObject * args,PyObject * kwargs)94 vs_translate(PyGimpVectorsStroke *self, PyObject *args, PyObject *kwargs)
95 {
96 double off_x, off_y;
97
98 static char *kwlist[] = { "off_x", "off_y", NULL };
99
100 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "dd:translate", kwlist,
101 &off_x, &off_y))
102 return NULL;
103
104 gimp_vectors_stroke_translate(self->vectors_ID, self->stroke, off_x, off_y);
105
106 Py_INCREF(Py_None);
107 return Py_None;
108 }
109
110 static PyObject *
vs_scale(PyGimpVectorsStroke * self,PyObject * args,PyObject * kwargs)111 vs_scale(PyGimpVectorsStroke *self, PyObject *args, PyObject *kwargs)
112 {
113 double scale_x, scale_y;
114
115 static char *kwlist[] = { "scale_x", "scale_y", NULL };
116
117 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "dd:scale", kwlist,
118 &scale_x, &scale_y))
119 return NULL;
120
121 gimp_vectors_stroke_scale(self->vectors_ID, self->stroke, scale_x, scale_y);
122
123 Py_INCREF(Py_None);
124 return Py_None;
125 }
126
127 static PyObject *
vs_rotate(PyGimpVectorsStroke * self,PyObject * args,PyObject * kwargs)128 vs_rotate(PyGimpVectorsStroke *self, PyObject *args, PyObject *kwargs)
129 {
130 double center_x, center_y, angle;
131
132 static char *kwlist[] = { "center_x", "center_y", "angle", NULL };
133
134 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ddd:rotate", kwlist,
135 ¢er_x, ¢er_y, &angle))
136 return NULL;
137
138 gimp_vectors_stroke_rotate(self->vectors_ID, self->stroke, center_x,
139 center_y, angle);
140
141 Py_INCREF(Py_None);
142 return Py_None;
143 }
144
145 static PyObject *
vs_flip(PyGimpVectorsStroke * self,PyObject * args,PyObject * kwargs)146 vs_flip(PyGimpVectorsStroke *self, PyObject *args, PyObject *kwargs)
147 {
148 int flip_type;
149 double axis;
150
151 static char *kwlist[] = { "flip_type", "axis", NULL };
152
153 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "id:flip", kwlist,
154 &flip_type, &axis))
155 return NULL;
156
157 gimp_vectors_stroke_flip(self->vectors_ID, self->stroke, flip_type, axis);
158
159 Py_INCREF(Py_None);
160 return Py_None;
161 }
162
163 static PyObject *
vs_flip_free(PyGimpVectorsStroke * self,PyObject * args,PyObject * kwargs)164 vs_flip_free(PyGimpVectorsStroke *self, PyObject *args, PyObject *kwargs)
165 {
166 double x1,y1,x2,y2;
167
168 static char *kwlist[] = { "x1", "y1", "x2", "y2", NULL };
169
170 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "dddd:flip_free", kwlist,
171 &x1, &y1, &x2, &y2))
172 return NULL;
173
174 gimp_vectors_stroke_flip_free(self->vectors_ID, self->stroke,
175 x1, y1, x2, y2);
176 Py_INCREF(Py_None);
177 return Py_None;
178 }
179
180
181
182 static PyObject *
vs_interpolate(PyGimpVectorsStroke * self,PyObject * args,PyObject * kwargs)183 vs_interpolate(PyGimpVectorsStroke *self, PyObject *args, PyObject *kwargs)
184 {
185 double precision;
186 double *coords;
187 int i, num_coords;
188 gboolean closed;
189 PyObject *ret, *ret_coords;
190
191 static char *kwlist[] = { "precision", NULL };
192
193 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "d:interpolate", kwlist,
194 &precision))
195 return NULL;
196
197 coords = gimp_vectors_stroke_interpolate(self->vectors_ID, self->stroke,
198 precision, &num_coords, &closed);
199
200 ret = PyTuple_New(2);
201 if (ret == NULL)
202 return NULL;
203
204 ret_coords = PyList_New(num_coords);
205 if (ret_coords == NULL) {
206 Py_DECREF(ret);
207 return NULL;
208 }
209
210 for (i = 0; i < num_coords; i++)
211 PyList_SetItem(ret_coords, i, PyFloat_FromDouble(coords[i]));
212
213 PyTuple_SetItem(ret, 0, ret_coords);
214 PyTuple_SetItem(ret, 1, PyBool_FromLong(closed));
215
216 return ret;
217 }
218
219 static PyMethodDef vs_methods[] = {
220 { "get_length", (PyCFunction)vs_get_length, METH_VARARGS | METH_KEYWORDS },
221 { "get_point_at_dist", (PyCFunction)vs_get_point_at_dist, METH_VARARGS | METH_KEYWORDS },
222 { "close", (PyCFunction)vs_close, METH_NOARGS },
223 { "translate", (PyCFunction)vs_translate, METH_VARARGS | METH_KEYWORDS },
224 { "scale", (PyCFunction)vs_scale, METH_VARARGS | METH_KEYWORDS },
225 { "rotate", (PyCFunction)vs_rotate, METH_VARARGS | METH_KEYWORDS },
226 { "flip", (PyCFunction)vs_flip, METH_VARARGS | METH_KEYWORDS },
227 { "flip_free", (PyCFunction)vs_flip_free, METH_VARARGS | METH_KEYWORDS },
228 { "interpolate", (PyCFunction)vs_interpolate, METH_VARARGS | METH_KEYWORDS },
229 { NULL, NULL, 0 }
230 };
231
232 static PyObject *
vs_get_ID(PyGimpVectorsStroke * self,void * closure)233 vs_get_ID(PyGimpVectorsStroke *self, void *closure)
234 {
235 return PyInt_FromLong(self->stroke);
236 }
237
238 static PyObject *
vs_get_vectors_ID(PyGimpVectorsStroke * self,void * closure)239 vs_get_vectors_ID(PyGimpVectorsStroke *self, void *closure)
240 {
241 return PyInt_FromLong(self->vectors_ID);
242 }
243
244 static PyObject *
vs_get_points(PyGimpVectorsStroke * self,void * closure)245 vs_get_points(PyGimpVectorsStroke *self, void *closure)
246 {
247 double *controlpoints;
248 int i, num_points;
249 gboolean closed;
250 PyObject *ret, *ret_points;
251
252 gimp_vectors_stroke_get_points(self->vectors_ID, self->stroke,
253 &num_points, &controlpoints, &closed);
254
255 ret = PyTuple_New(2);
256 if (ret == NULL)
257 return NULL;
258
259 ret_points = PyList_New(num_points);
260 if (ret_points == NULL) {
261 Py_DECREF(ret);
262 return NULL;
263 }
264
265 for (i = 0; i < num_points; i++)
266 PyList_SetItem(ret_points, i, PyFloat_FromDouble(controlpoints[i]));
267
268 PyTuple_SetItem(ret, 0, ret_points);
269 PyTuple_SetItem(ret, 1, PyBool_FromLong(closed));
270
271 return ret;
272 }
273
274 static PyGetSetDef vs_getsets[] = {
275 { "ID", (getter)vs_get_ID, (setter)0 },
276 { "vectors_ID", (getter)vs_get_vectors_ID, (setter)0 },
277 { "points", (getter)vs_get_points, (setter)0 },
278 { NULL, (getter)0, (setter)0 }
279 };
280
281 static void
vs_dealloc(PyGimpVectorsStroke * self)282 vs_dealloc(PyGimpVectorsStroke *self)
283 {
284 PyObject_DEL(self);
285 }
286
287 static PyObject *
vs_repr(PyGimpVectorsStroke * self)288 vs_repr(PyGimpVectorsStroke *self)
289 {
290 PyObject *s;
291 char *name;
292
293 name = gimp_item_get_name(self->vectors_ID);
294 s = PyString_FromFormat("<gimp.VectorsStroke %d of gimp.Vectors '%s'>",
295 self->stroke, name ? name : "(null)");
296 g_free(name);
297
298 return s;
299 }
300
301 static int
vs_cmp(PyGimpVectorsStroke * self,PyGimpVectorsStroke * other)302 vs_cmp(PyGimpVectorsStroke *self, PyGimpVectorsStroke *other)
303 {
304 if (self->vectors_ID == other->vectors_ID) {
305 if (self->stroke == other->stroke)
306 return 0;
307 if (self->stroke > other->stroke)
308 return -1;
309 return 1;
310 }
311 if (self->vectors_ID > other->vectors_ID)
312 return -1;
313 return 1;
314 }
315
316 PyTypeObject PyGimpVectorsStroke_Type = {
317 PyObject_HEAD_INIT(NULL)
318 0, /* ob_size */
319 "gimp.VectorsStroke", /* tp_name */
320 sizeof(PyGimpVectorsStroke), /* tp_basicsize */
321 0, /* tp_itemsize */
322 /* methods */
323 (destructor)vs_dealloc, /* tp_dealloc */
324 (printfunc)0, /* tp_print */
325 (getattrfunc)0, /* tp_getattr */
326 (setattrfunc)0, /* tp_setattr */
327 (cmpfunc)vs_cmp, /* tp_compare */
328 (reprfunc)vs_repr, /* tp_repr */
329 0, /* tp_as_number */
330 0, /* tp_as_sequence */
331 0, /* tp_as_mapping */
332 (hashfunc)0, /* tp_hash */
333 (ternaryfunc)0, /* tp_call */
334 (reprfunc)0, /* tp_str */
335 (getattrofunc)0, /* tp_getattro */
336 (setattrofunc)0, /* tp_setattro */
337 0, /* tp_as_buffer */
338 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
339 NULL, /* Documentation string */
340 (traverseproc)0, /* tp_traverse */
341 (inquiry)0, /* tp_clear */
342 (richcmpfunc)0, /* tp_richcompare */
343 0, /* tp_weaklistoffset */
344 (getiterfunc)0, /* tp_iter */
345 (iternextfunc)0, /* tp_iternext */
346 vs_methods, /* tp_methods */
347 0, /* tp_members */
348 vs_getsets, /* tp_getset */
349 (PyTypeObject *)0, /* tp_base */
350 (PyObject *)0, /* tp_dict */
351 0, /* tp_descr_get */
352 0, /* tp_descr_set */
353 0, /* tp_dictoffset */
354 (initproc)0, /* tp_init */
355 (allocfunc)0, /* tp_alloc */
356 (newfunc)0, /* tp_new */
357 };
358
359
360 static PyObject *
vbs_new_moveto(PyTypeObject * type,PyObject * args,PyObject * kwargs)361 vbs_new_moveto(PyTypeObject *type, PyObject *args, PyObject *kwargs)
362 {
363 PyGimpVectors *vectors;
364 double x0, y0;
365 int stroke;
366
367 static char *kwlist[] = { "vectors", "x0", "y0", NULL };
368
369 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
370 "O!dd:new_moveto", kwlist,
371 &PyGimpVectors_Type, &vectors,
372 &x0, &y0))
373 return NULL;
374
375 stroke = gimp_vectors_bezier_stroke_new_moveto(vectors->ID, x0, y0);
376
377 return vectors_bezier_stroke_new(vectors, stroke);
378 }
379
380 static PyObject *
vbs_new_ellipse(PyTypeObject * type,PyObject * args,PyObject * kwargs)381 vbs_new_ellipse(PyTypeObject *type, PyObject *args, PyObject *kwargs)
382 {
383 PyGimpVectors *vectors;
384 double x0, y0, radius_x, radius_y, angle;
385 int stroke;
386
387 static char *kwlist[] = { "vectors", "x0", "y0", "radius_x", "radius_y",
388 "angle", NULL };
389
390 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
391 "O!ddddd:new_ellipse", kwlist,
392 &PyGimpVectors_Type, &vectors,
393 &x0, &y0, &radius_x, &radius_y, &angle))
394 return NULL;
395
396 stroke = gimp_vectors_bezier_stroke_new_ellipse(vectors->ID, x0, y0,
397 radius_x, radius_y, angle);
398
399 return vectors_bezier_stroke_new(vectors, stroke);
400 }
401
402 static PyObject *
vbs_lineto(PyGimpVectorsStroke * self,PyObject * args,PyObject * kwargs)403 vbs_lineto(PyGimpVectorsStroke *self, PyObject *args, PyObject *kwargs)
404 {
405 double x0, y0;
406
407 static char *kwlist[] = { "x0", "y0", NULL };
408
409 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
410 "dd:lineto", kwlist,
411 &x0, &y0))
412 return NULL;
413
414 gimp_vectors_bezier_stroke_lineto(self->vectors_ID, self->stroke, x0, y0);
415
416 Py_INCREF(Py_None);
417 return Py_None;
418 }
419
420 static PyObject *
vbs_conicto(PyGimpVectorsStroke * self,PyObject * args,PyObject * kwargs)421 vbs_conicto(PyGimpVectorsStroke *self, PyObject *args, PyObject *kwargs)
422 {
423 double x0, y0, x1, y1;
424
425 static char *kwlist[] = { "x0", "y0", "x1", "y1", NULL };
426
427 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
428 "dddd:conicto", kwlist,
429 &x0, &y0, &x1, &y1))
430 return NULL;
431
432 gimp_vectors_bezier_stroke_conicto(self->vectors_ID, self->stroke,
433 x0, y0, x1, y1);
434
435 Py_INCREF(Py_None);
436 return Py_None;
437 }
438
439 static PyObject *
vbs_cubicto(PyGimpVectorsStroke * self,PyObject * args,PyObject * kwargs)440 vbs_cubicto(PyGimpVectorsStroke *self, PyObject *args, PyObject *kwargs)
441 {
442 double x0, y0, x1, y1, x2, y2;
443
444 static char *kwlist[] = { "x0", "y0", "x1", "y1", "x2", "y2", NULL };
445
446 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
447 "dddddd:cubicto", kwlist,
448 &x0, &y0, &x1, &y1, &x2, &y2))
449 return NULL;
450
451 gimp_vectors_bezier_stroke_cubicto(self->vectors_ID, self->stroke,
452 x0, y0, x1, y1, x2, y2);
453
454 Py_INCREF(Py_None);
455 return Py_None;
456 }
457
458 static PyMethodDef vbs_methods[] = {
459 { "new_moveto", (PyCFunction)vbs_new_moveto, METH_VARARGS | METH_KEYWORDS | METH_CLASS },
460 { "new_ellipse", (PyCFunction)vbs_new_ellipse, METH_VARARGS | METH_KEYWORDS | METH_CLASS },
461 { "lineto", (PyCFunction)vbs_lineto, METH_VARARGS | METH_KEYWORDS },
462 { "conicto", (PyCFunction)vbs_conicto, METH_VARARGS | METH_KEYWORDS },
463 { "cubicto", (PyCFunction)vbs_cubicto, METH_VARARGS | METH_KEYWORDS },
464 { NULL, NULL, 0 }
465 };
466
467 static PyObject *
vbs_repr(PyGimpVectorsStroke * self)468 vbs_repr(PyGimpVectorsStroke *self)
469 {
470 PyObject *s;
471 char *name;
472
473 name = gimp_item_get_name(self->vectors_ID);
474 s = PyString_FromFormat("<gimp.VectorsBezierStroke %d of gimp.Vectors '%s'>",
475 self->stroke, name ? name : "(null)");
476 g_free(name);
477
478 return s;
479 }
480
481 static int
vbs_init(PyGimpVectorsStroke * self,PyObject * args,PyObject * kwargs)482 vbs_init(PyGimpVectorsStroke *self, PyObject *args, PyObject *kwargs)
483 {
484 PyGimpVectors *vectors;
485 double *controlpoints;
486 gboolean closed = FALSE;
487 PyObject *py_controlpoints, *item;
488 int i, num_points;
489
490 static char *kwlist[] = { "vectors", "controlpoints", "closed", NULL };
491
492 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
493 "O!O|i:gimp.VectorsBezierStroke.__init__",
494 kwlist,
495 &PyGimpVectors_Type, &vectors,
496 &py_controlpoints, &closed))
497 return -1;
498
499 if (!PySequence_Check(py_controlpoints)) {
500 PyErr_SetString(PyExc_TypeError,
501 "controlpoints must be a sequence");
502 return -1;
503 }
504
505 num_points = PySequence_Length(py_controlpoints);
506 controlpoints = g_new(gdouble, num_points);
507
508 for (i = 0; i < num_points; i++) {
509 item = PySequence_GetItem(py_controlpoints, i);
510
511 if (!PyFloat_Check(item)) {
512 PyErr_SetString(PyExc_TypeError,
513 "controlpoints must be a sequence of floats");
514 g_free(controlpoints);
515 return -1;
516 }
517
518 controlpoints[i] = PyFloat_AsDouble(item);
519 }
520
521 self->vectors_ID = vectors->ID;
522 self->stroke =
523 gimp_vectors_stroke_new_from_points(self->vectors_ID,
524 GIMP_VECTORS_STROKE_TYPE_BEZIER,
525 num_points, controlpoints, closed);
526
527 g_free(controlpoints);
528
529 return 0;
530 }
531
532 PyTypeObject PyGimpVectorsBezierStroke_Type = {
533 PyObject_HEAD_INIT(NULL)
534 0, /* ob_size */
535 "gimp.VectorsBezierStroke", /* tp_name */
536 sizeof(PyGimpVectorsStroke), /* tp_basicsize */
537 0, /* tp_itemsize */
538 /* methods */
539 (destructor)vs_dealloc, /* tp_dealloc */
540 (printfunc)0, /* tp_print */
541 (getattrfunc)0, /* tp_getattr */
542 (setattrfunc)0, /* tp_setattr */
543 (cmpfunc)vs_cmp, /* tp_compare */
544 (reprfunc)vbs_repr, /* tp_repr */
545 0, /* tp_as_number */
546 0, /* tp_as_sequence */
547 0, /* tp_as_mapping */
548 (hashfunc)0, /* tp_hash */
549 (ternaryfunc)0, /* tp_call */
550 (reprfunc)0, /* tp_str */
551 (getattrofunc)0, /* tp_getattro */
552 (setattrofunc)0, /* tp_setattro */
553 0, /* tp_as_buffer */
554 Py_TPFLAGS_DEFAULT, /* tp_flags */
555 NULL, /* Documentation string */
556 (traverseproc)0, /* tp_traverse */
557 (inquiry)0, /* tp_clear */
558 (richcmpfunc)0, /* tp_richcompare */
559 0, /* tp_weaklistoffset */
560 (getiterfunc)0, /* tp_iter */
561 (iternextfunc)0, /* tp_iternext */
562 vbs_methods, /* tp_methods */
563 0, /* tp_members */
564 0, /* tp_getset */
565 &PyGimpVectorsStroke_Type, /* tp_base */
566 (PyObject *)0, /* tp_dict */
567 0, /* tp_descr_get */
568 0, /* tp_descr_set */
569 0, /* tp_dictoffset */
570 (initproc)vbs_init, /* tp_init */
571 (allocfunc)0, /* tp_alloc */
572 (newfunc)0, /* tp_new */
573 };
574
575 static PyObject *
vectors_bezier_stroke_new(PyGimpVectors * vectors,int stroke)576 vectors_bezier_stroke_new(PyGimpVectors *vectors, int stroke)
577 {
578 PyGimpVectorsStroke *self;
579
580 self = PyObject_NEW(PyGimpVectorsStroke, &PyGimpVectorsBezierStroke_Type);
581
582 if (self == NULL)
583 return NULL;
584
585 self->vectors_ID = vectors->ID;
586 self->stroke = stroke;
587
588 return (PyObject *)self;
589 }
590
591
592 static PyObject *
vectors_remove_stroke(PyGimpVectors * self,PyObject * args,PyObject * kwargs)593 vectors_remove_stroke(PyGimpVectors *self, PyObject *args, PyObject *kwargs)
594 {
595 int stroke_id ;
596 /* PyGimpVectorsStroke *stroke; */
597 PyObject *stroke = NULL;
598
599 static char *kwlist[] = { "stroke", NULL };
600
601 PyArg_ParseTupleAndKeywords(args, kwargs, "O:remove_stroke", kwlist, &stroke);
602
603 if (PyInt_Check(stroke))
604 stroke_id = PyInt_AsLong(stroke);
605 else if (PyObject_IsInstance(stroke, (PyObject *) &PyGimpVectorsStroke_Type))
606 stroke_id = ((PyGimpVectorsStroke *) stroke)->stroke;
607 else {
608 PyErr_SetString(PyExc_TypeError, "stroke must be a gimp.VectorsBezierStroke object or an Integer");
609 return NULL;
610 }
611
612 gimp_vectors_remove_stroke(self->ID, stroke_id);
613
614 Py_INCREF(Py_None);
615 return Py_None;
616 }
617
618 static PyObject *
vectors_to_selection(PyGimpVectors * self,PyObject * args,PyObject * kwargs)619 vectors_to_selection(PyGimpVectors *self, PyObject *args, PyObject *kwargs)
620 {
621 GimpChannelOps operation = GIMP_CHANNEL_OP_REPLACE;
622 gboolean antialias = TRUE, feather = FALSE;
623 double feather_radius_x = 0.0, feather_radius_y = 0.0;
624
625 static char *kwlist[] = { "operation", "antialias", "feather",
626 "feather_radius_x", "feather_radius_y", NULL };
627
628 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
629 "|iiidd:to_selection", kwlist,
630 &operation, &antialias, &feather,
631 &feather_radius_x, &feather_radius_y))
632 return NULL;
633
634 gimp_context_push();
635 gimp_context_set_antialias(antialias);
636 gimp_context_set_feather(feather);
637 gimp_context_set_feather_radius(feather_radius_x, feather_radius_y);
638 gimp_image_select_item(gimp_item_get_image(self->ID), operation, self->ID);
639 gimp_context_pop();
640
641 Py_INCREF(Py_None);
642 return Py_None;
643 }
644
645 static PyObject *
vectors_parasite_find(PyGimpVectors * self,PyObject * args)646 vectors_parasite_find(PyGimpVectors *self, PyObject *args)
647 {
648 char *name;
649
650 if (!PyArg_ParseTuple(args, "s:parasite_find", &name))
651 return NULL;
652
653 return pygimp_parasite_new(gimp_item_get_parasite(self->ID, name));
654 }
655
656 static PyObject *
vectors_parasite_attach(PyGimpVectors * self,PyObject * args)657 vectors_parasite_attach(PyGimpVectors *self, PyObject *args)
658 {
659 PyGimpParasite *parasite;
660
661 if (!PyArg_ParseTuple(args, "O!:parasite_attach", &PyGimpParasite_Type,
662 ¶site))
663 return NULL;
664
665 if (!gimp_item_attach_parasite(self->ID, parasite->para)) {
666 PyErr_Format(pygimp_error,
667 "could not attach parasite '%s' to vectors (ID %d)",
668 parasite->para->name, self->ID);
669 return NULL;
670 }
671
672 Py_INCREF(Py_None);
673 return Py_None;
674 }
675
676 static PyObject *
vectors_parasite_detach(PyGimpVectors * self,PyObject * args)677 vectors_parasite_detach(PyGimpVectors *self, PyObject *args)
678 {
679 char *name;
680
681 if (!PyArg_ParseTuple(args, "s:parasite_detach", &name))
682 return NULL;
683
684 if (!gimp_item_detach_parasite(self->ID, name)) {
685 PyErr_Format(pygimp_error,
686 "could not detach parasite '%s' from vectors (ID %d)",
687 name, self->ID);
688 return NULL;
689 }
690
691 Py_INCREF(Py_None);
692 return Py_None;
693 }
694
695 static PyObject *
vectors_parasite_list(PyGimpVectors * self)696 vectors_parasite_list(PyGimpVectors *self)
697 {
698 gint num_parasites;
699 gchar **parasites;
700 PyObject *ret;
701 gint i;
702
703 parasites = gimp_item_get_parasite_list(self->ID, &num_parasites);
704
705 ret = PyTuple_New(num_parasites);
706
707 for (i = 0; i < num_parasites; i++)
708 PyTuple_SetItem(ret, i, PyString_FromString(parasites[i]));
709
710 g_strfreev(parasites);
711 return ret;
712 }
713
714 static PyMethodDef vectors_methods[] = {
715 { "remove_stroke",
716 (PyCFunction)vectors_remove_stroke,
717 METH_VARARGS | METH_KEYWORDS },
718 { "to_selection",
719 (PyCFunction)vectors_to_selection,
720 METH_VARARGS | METH_KEYWORDS },
721 { "parasite_find",
722 (PyCFunction)vectors_parasite_find,
723 METH_VARARGS },
724 { "parasite_attach",
725 (PyCFunction)vectors_parasite_attach,
726 METH_VARARGS },
727 { "parasite_detach",
728 (PyCFunction)vectors_parasite_detach,
729 METH_VARARGS },
730 { "parasite_list",
731 (PyCFunction)vectors_parasite_list,
732 METH_NOARGS },
733 { NULL, NULL, 0 }
734 };
735
736 static PyObject *
vectors_get_image(PyGimpVectors * self,void * closure)737 vectors_get_image(PyGimpVectors *self, void *closure)
738 {
739 return pygimp_image_new(gimp_item_get_image(self->ID));
740 }
741
742 static PyObject *
vectors_get_ID(PyGimpVectors * self,void * closure)743 vectors_get_ID(PyGimpVectors *self, void *closure)
744 {
745 return PyInt_FromLong(self->ID);
746 }
747
748 static PyObject *
vectors_get_name(PyGimpVectors * self,void * closure)749 vectors_get_name(PyGimpVectors *self, void *closure)
750 {
751 return PyString_FromString(gimp_item_get_name(self->ID));
752 }
753
754 static int
vectors_set_name(PyGimpVectors * self,PyObject * value,void * closure)755 vectors_set_name(PyGimpVectors *self, PyObject *value, void *closure)
756 {
757 if (value == NULL) {
758 PyErr_SetString(PyExc_TypeError, "cannot delete name");
759 return -1;
760 }
761
762 if (!PyString_Check(value) && !PyUnicode_Check(value)) {
763 PyErr_SetString(PyExc_TypeError, "type mismatch");
764 return -1;
765 }
766
767 gimp_item_set_name(self->ID, PyString_AsString(value));
768
769 return 0;
770 }
771
772 static PyObject *
vectors_get_visible(PyGimpVectors * self,void * closure)773 vectors_get_visible(PyGimpVectors *self, void *closure)
774 {
775 return PyBool_FromLong(gimp_item_get_visible(self->ID));
776 }
777
778 static int
vectors_set_visible(PyGimpVectors * self,PyObject * value,void * closure)779 vectors_set_visible(PyGimpVectors *self, PyObject *value, void *closure)
780 {
781 if (value == NULL) {
782 PyErr_SetString(PyExc_TypeError, "cannot delete visible");
783 return -1;
784 }
785
786 if (!PyInt_Check(value)) {
787 PyErr_SetString(PyExc_TypeError, "type mismatch");
788 return -1;
789 }
790
791 gimp_item_set_visible(self->ID, PyInt_AsLong(value));
792
793 return 0;
794 }
795
796 static PyObject *
vectors_get_linked(PyGimpVectors * self,void * closure)797 vectors_get_linked(PyGimpVectors *self, void *closure)
798 {
799 return PyBool_FromLong(gimp_item_get_linked(self->ID));
800 }
801
802 static int
vectors_set_linked(PyGimpVectors * self,PyObject * value,void * closure)803 vectors_set_linked(PyGimpVectors *self, PyObject *value, void *closure)
804 {
805 if (value == NULL) {
806 PyErr_SetString(PyExc_TypeError, "cannot delete linked");
807 return -1;
808 }
809
810 if (!PyInt_Check(value)) {
811 PyErr_SetString(PyExc_TypeError, "type mismatch");
812 return -1;
813 }
814
815 gimp_item_set_linked(self->ID, PyInt_AsLong(value));
816
817 return 0;
818 }
819
820 static PyObject *
vectors_get_tattoo(PyGimpVectors * self,void * closure)821 vectors_get_tattoo(PyGimpVectors *self, void *closure)
822 {
823 return PyInt_FromLong(gimp_item_get_tattoo(self->ID));
824 }
825
826 static int
vectors_set_tattoo(PyGimpVectors * self,PyObject * value,void * closure)827 vectors_set_tattoo(PyGimpVectors *self, PyObject *value, void *closure)
828 {
829 if (value == NULL) {
830 PyErr_SetString(PyExc_TypeError, "cannot delete tattoo");
831 return -1;
832 }
833
834 if (!PyInt_Check(value)) {
835 PyErr_SetString(PyExc_TypeError, "type mismatch");
836 return -1;
837 }
838
839 gimp_item_set_tattoo(self->ID, PyInt_AsLong(value));
840
841 return 0;
842 }
843
844 static PyObject *
vectors_get_strokes(PyGimpVectors * self,void * closure)845 vectors_get_strokes(PyGimpVectors *self, void *closure)
846 {
847 int *strokes;
848 int i, num_strokes;
849 PyObject *ret;
850
851 strokes = gimp_vectors_get_strokes(self->ID, &num_strokes);
852
853 ret = PyList_New(num_strokes);
854 if (ret == NULL)
855 return NULL;
856
857 for (i = 0; i < num_strokes; i++)
858 PyList_SetItem(ret, i, vectors_bezier_stroke_new(self, strokes[i]));
859
860 g_free(strokes);
861
862 return ret;
863 }
864
865 static PyGetSetDef vectors_getsets[] = {
866 { "ID", (getter)vectors_get_ID, (setter)0 },
867 { "image", (getter)vectors_get_image, (setter)0 },
868 { "name", (getter)vectors_get_name, (setter)vectors_set_name },
869 { "visible", (getter)vectors_get_visible, (setter)vectors_set_visible },
870 { "linked", (getter)vectors_get_linked, (setter)vectors_set_linked },
871 { "tattoo", (getter)vectors_get_tattoo, (setter)vectors_set_tattoo },
872 { "strokes", (getter)vectors_get_strokes, (setter)0 },
873 { NULL, (getter)0, (setter)0 }
874 };
875
876 static void
vectors_dealloc(PyGimpVectors * self)877 vectors_dealloc(PyGimpVectors *self)
878 {
879 PyObject_DEL(self);
880 }
881
882 static PyObject *
vectors_repr(PyGimpVectors * self)883 vectors_repr(PyGimpVectors *self)
884 {
885 PyObject *s;
886 char *name;
887
888 name = gimp_item_get_name(self->ID);
889 s = PyString_FromFormat("<gimp.Vectors '%s'>", name ? name : "(null)");
890 g_free(name);
891
892 return s;
893 }
894
895 static int
vectors_cmp(PyGimpVectors * self,PyGimpVectors * other)896 vectors_cmp(PyGimpVectors *self, PyGimpVectors *other)
897 {
898 if (self->ID == other->ID)
899 return 0;
900 if (self->ID > other->ID)
901 return -1;
902 return 1;
903 }
904
905 static int
vectors_init(PyGimpVectors * self,PyObject * args,PyObject * kwargs)906 vectors_init(PyGimpVectors *self, PyObject *args, PyObject *kwargs)
907 {
908 PyGimpImage *img;
909 char *name;
910
911 static char *kwlist[] = { "image", "name", NULL };
912
913 if (!PyArg_ParseTupleAndKeywords(args, kwargs,
914 "O!s:gimp.Vectors.__init__",
915 kwlist,
916 &PyGimpImage_Type, &img, &name))
917 return -1;
918
919 self->ID = gimp_vectors_new(img->ID, name);
920
921 if (self->ID < 0) {
922 PyErr_Format(pygimp_error,
923 "could not create vectors '%s' on image (ID %d)",
924 name, img->ID);
925 return -1;
926 }
927
928 return 0;
929 }
930
931 PyTypeObject PyGimpVectors_Type = {
932 PyObject_HEAD_INIT(NULL)
933 0, /* ob_size */
934 "gimp.Vectors", /* tp_name */
935 sizeof(PyGimpVectors), /* tp_basicsize */
936 0, /* tp_itemsize */
937 /* methods */
938 (destructor)vectors_dealloc, /* tp_dealloc */
939 (printfunc)0, /* tp_print */
940 (getattrfunc)0, /* tp_getattr */
941 (setattrfunc)0, /* tp_setattr */
942 (cmpfunc)vectors_cmp, /* tp_compare */
943 (reprfunc)vectors_repr, /* tp_repr */
944 0, /* tp_as_number */
945 0, /* tp_as_sequence */
946 0, /* tp_as_mapping */
947 (hashfunc)0, /* tp_hash */
948 (ternaryfunc)0, /* tp_call */
949 (reprfunc)0, /* tp_str */
950 (getattrofunc)0, /* tp_getattro */
951 (setattrofunc)0, /* tp_setattro */
952 0, /* tp_as_buffer */
953 Py_TPFLAGS_DEFAULT, /* tp_flags */
954 NULL, /* Documentation string */
955 (traverseproc)0, /* tp_traverse */
956 (inquiry)0, /* tp_clear */
957 (richcmpfunc)0, /* tp_richcompare */
958 0, /* tp_weaklistoffset */
959 (getiterfunc)0, /* tp_iter */
960 (iternextfunc)0, /* tp_iternext */
961 vectors_methods, /* tp_methods */
962 0, /* tp_members */
963 vectors_getsets, /* tp_getset */
964 &PyGimpItem_Type, /* tp_base */
965 (PyObject *)0, /* tp_dict */
966 0, /* tp_descr_get */
967 0, /* tp_descr_set */
968 0, /* tp_dictoffset */
969 (initproc)vectors_init, /* tp_init */
970 (allocfunc)0, /* tp_alloc */
971 (newfunc)0, /* tp_new */
972 };
973
974 PyObject *
pygimp_vectors_new(gint32 ID)975 pygimp_vectors_new(gint32 ID)
976 {
977 PyGimpVectors *self;
978
979 if (!gimp_item_is_valid(ID)) {
980 Py_INCREF(Py_None);
981 return Py_None;
982 }
983
984 self = PyObject_NEW(PyGimpVectors, &PyGimpVectors_Type);
985
986 if (self == NULL)
987 return NULL;
988
989 self->ID = ID;
990
991 return (PyObject *)self;
992 }
993