COLLADA branch: merge from trunk -r 24522:24758.
[blender.git] / source / blender / python / generic / IDProp.c
1 /**
2  * $Id: IDProp.c
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  *
21  * Contributor(s): Joseph Eagar, Campbell Barton
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 #include "DNA_ID.h"
27
28 #include "BKE_idprop.h"
29
30 #include "IDProp.h"
31 // #include "gen_utils.h"
32
33 #include "MEM_guardedalloc.h"
34
35 #define BSTR_EQ(a, b)   (*(a) == *(b) && !strcmp(a, b))
36
37 /*** Function to wrap ID properties ***/
38 PyObject *BPy_Wrap_IDProperty(ID *id, IDProperty *prop, IDProperty *parent);
39
40 extern PyTypeObject IDArray_Type;
41 extern PyTypeObject IDGroup_Iter_Type;
42
43 /*********************** ID Property Main Wrapper Stuff ***************/
44
45 PyObject *IDGroup_repr( BPy_IDProperty *self )
46 {
47         return PyUnicode_FromFormat( "<bpy ID property from \"%s\">", self->id->name);
48 }
49
50 extern PyTypeObject IDGroup_Type;
51
52 PyObject *BPy_IDGroup_WrapData( ID *id, IDProperty *prop )
53 {
54         switch ( prop->type ) {
55                 case IDP_STRING:
56                         return PyUnicode_FromString( prop->data.pointer );
57                 case IDP_INT:
58                         return PyLong_FromLong( (long)prop->data.val );
59                 case IDP_FLOAT:
60                         return PyFloat_FromDouble( (double)(*(float*)(&prop->data.val)) );
61                 case IDP_DOUBLE:
62                         return PyFloat_FromDouble( (*(double*)(&prop->data.val)) );
63                 case IDP_GROUP:
64                         /*blegh*/
65                         {
66                                 BPy_IDProperty *group = PyObject_New(BPy_IDProperty, &IDGroup_Type);
67                                 group->id = id;
68                                 group->prop = prop;
69                                 return (PyObject*) group;
70                         }
71                 case IDP_ARRAY:
72                         {
73                                 BPy_IDProperty *array = PyObject_New(BPy_IDProperty, &IDArray_Type);
74                                 array->id = id;
75                                 array->prop = prop;
76                                 return (PyObject*) array;
77                         }
78         }
79         Py_RETURN_NONE;
80 }
81
82 int BPy_IDGroup_SetData(BPy_IDProperty *self, IDProperty *prop, PyObject *value)
83 {
84         switch (prop->type) {
85                 case IDP_STRING:
86                 {
87                         char *st;
88                         if (!PyUnicode_Check(value)) {
89                                 PyErr_SetString(PyExc_TypeError, "expected a string!");
90                                 return -1;
91                         }
92
93                         st = _PyUnicode_AsString(value);
94                         IDP_ResizeArray(prop, strlen(st)+1);
95                         strcpy(prop->data.pointer, st);
96                         return 0;
97                 }
98
99                 case IDP_INT:
100                 {
101                         int ivalue= PyLong_AsSsize_t(value);
102                         if (ivalue==-1 && PyErr_Occurred()) {
103                                 PyErr_SetString(PyExc_TypeError, "expected an int type");
104                                 return -1;
105                         }
106                         prop->data.val = ivalue;
107                         break;
108                 }
109                 case IDP_FLOAT:
110                 {
111                         float fvalue= (float)PyFloat_AsDouble(value);
112                         if (fvalue==-1 && PyErr_Occurred()) {
113                                 PyErr_SetString(PyExc_TypeError, "expected a float");
114                                 return -1;
115                         }
116                         *(float*)&self->prop->data.val = fvalue;
117                         break;
118                 }
119                 case IDP_DOUBLE:
120                 {
121                         double dvalue= PyFloat_AsDouble(value);
122                         if (dvalue==-1 && PyErr_Occurred()) {
123                                 PyErr_SetString(PyExc_TypeError, "expected a float");
124                                 return -1;
125                         }
126                         *(double*)&self->prop->data.val = dvalue;
127                         break;
128                 }
129                 default:
130                         PyErr_SetString(PyExc_AttributeError, "attempt to set read-only attribute!");
131                         return -1;
132         }
133         return 0;
134 }
135
136 PyObject *BPy_IDGroup_GetName(BPy_IDProperty *self, void *bleh)
137 {
138         return PyUnicode_FromString(self->prop->name);
139 }
140
141 static int BPy_IDGroup_SetName(BPy_IDProperty *self, PyObject *value, void *bleh)
142 {
143         char *st;
144         if (!PyUnicode_Check(value)) {
145                 PyErr_SetString(PyExc_TypeError, "expected a string!");
146                 return -1;
147         }
148
149         st = _PyUnicode_AsString(value);
150         if (strlen(st) >= MAX_IDPROP_NAME) {
151                 PyErr_SetString(PyExc_TypeError, "string length cannot exceed 31 characters!");
152                 return -1;
153         }
154
155         strcpy(self->prop->name, st);
156         return 0;
157 }
158
159 #if 0
160 static PyObject *BPy_IDGroup_GetType(BPy_IDProperty *self)
161 {
162         return PyLong_FromSsize_t(self->prop->type);
163 }
164 #endif
165
166 static PyGetSetDef BPy_IDGroup_getseters[] = {
167         {"name",
168          (getter)BPy_IDGroup_GetName, (setter)BPy_IDGroup_SetName,
169          "The name of this Group.",
170          NULL},
171          {NULL, NULL, NULL, NULL, NULL}
172 };
173
174 static Py_ssize_t BPy_IDGroup_Map_Len(BPy_IDProperty *self)
175 {
176         if (self->prop->type != IDP_GROUP) {
177                 PyErr_SetString( PyExc_TypeError, "len() of unsized object");
178                 return -1;
179         }
180
181         return self->prop->len;
182 }
183
184 static PyObject *BPy_IDGroup_Map_GetItem(BPy_IDProperty *self, PyObject *item)
185 {
186         IDProperty *idprop;
187         char *name;
188
189         if (self->prop->type  != IDP_GROUP) {
190                 PyErr_SetString( PyExc_TypeError, "unsubscriptable object");
191                 return NULL;
192         }
193
194         name= _PyUnicode_AsString(item);
195
196         if (name == NULL) {
197                 PyErr_SetString( PyExc_TypeError, "only strings are allowed as keys of ID properties");
198                 return NULL;
199         }
200
201         idprop= IDP_GetPropertyFromGroup(self->prop, name);
202
203         if(idprop==NULL) {
204                 PyErr_SetString( PyExc_KeyError, "key not in subgroup dict");
205                 return NULL;
206         }
207
208         return BPy_IDGroup_WrapData(self->id, idprop);
209
210 }
211
212 /*returns NULL on success, error string on failure*/
213 char *BPy_IDProperty_Map_ValidateAndCreate(char *name, IDProperty *group, PyObject *ob)
214 {
215         IDProperty *prop = NULL;
216         IDPropertyTemplate val = {0};
217
218         if(strlen(name) >= sizeof(group->name))
219                 return "the length of IDProperty names is limited to 31 characters";
220
221         if (PyFloat_Check(ob)) {
222                 val.d = PyFloat_AsDouble(ob);
223                 prop = IDP_New(IDP_DOUBLE, val, name);
224         } else if (PyLong_Check(ob)) {
225                 val.i = (int) PyLong_AsSsize_t(ob);
226                 prop = IDP_New(IDP_INT, val, name);
227         } else if (PyUnicode_Check(ob)) {
228                 val.str = _PyUnicode_AsString(ob);
229                 prop = IDP_New(IDP_STRING, val, name);
230         } else if (PySequence_Check(ob)) {
231                 PyObject *item;
232                 int i;
233
234                 /*validate sequence and derive type.
235                 we assume IDP_INT unless we hit a float
236                 number; then we assume it's */
237                 val.array.type = IDP_INT;
238                 val.array.len = PySequence_Length(ob);
239                 for (i=0; i<val.array.len; i++) {
240                         item = PySequence_GetItem(ob, i);
241                         if (PyFloat_Check(item)) val.array.type = IDP_DOUBLE;
242                         else if (!PyLong_Check(item)) {
243                                 Py_XDECREF(item);
244                                 return "only floats and ints are allowed in ID property arrays";
245                         }
246                         Py_XDECREF(item);
247                 }
248
249                 prop = IDP_New(IDP_ARRAY, val, name);
250                 for (i=0; i<val.array.len; i++) {
251                         item = PySequence_GetItem(ob, i);
252                         if (val.array.type == IDP_INT) {
253                                 ((int*)prop->data.pointer)[i] = (int)PyLong_AsSsize_t(item);
254                         } else {
255                                 ((double*)prop->data.pointer)[i] = (float)PyFloat_AsDouble(item);
256                         }
257                 }
258         } else if (PyMapping_Check(ob)) {
259                 PyObject *keys, *vals, *key, *pval;
260                 int i, len;
261                 /*yay! we get into recursive stuff now!*/
262                 keys = PyMapping_Keys(ob);
263                 vals = PyMapping_Values(ob);
264
265                 /*we allocate the group first; if we hit any invalid data,
266                   we can delete it easily enough.*/
267                 prop = IDP_New(IDP_GROUP, val, name);
268                 len = PyMapping_Length(ob);
269                 for (i=0; i<len; i++) {
270                         key = PySequence_GetItem(keys, i);
271                         pval = PySequence_GetItem(vals, i);
272                         if (!PyUnicode_Check(key)) {
273                                 IDP_FreeProperty(prop);
274                                 MEM_freeN(prop);
275                                 Py_XDECREF(keys);
276                                 Py_XDECREF(vals);
277                                 Py_XDECREF(key);
278                                 Py_XDECREF(pval);
279                                 return "invalid element in subgroup dict template!";
280                         }
281                         if (BPy_IDProperty_Map_ValidateAndCreate(_PyUnicode_AsString(key), prop, pval)) {
282                                 IDP_FreeProperty(prop);
283                                 MEM_freeN(prop);
284                                 Py_XDECREF(keys);
285                                 Py_XDECREF(vals);
286                                 Py_XDECREF(key);
287                                 Py_XDECREF(pval);
288                                 return "invalid element in subgroup dict template!";
289                         }
290                         Py_XDECREF(key);
291                         Py_XDECREF(pval);
292                 }
293                 Py_XDECREF(keys);
294                 Py_XDECREF(vals);
295         } else return "invalid property value";
296
297         IDP_ReplaceInGroup(group, prop);
298         return NULL;
299 }
300
301 int BPy_Wrap_SetMapItem(IDProperty *prop, PyObject *key, PyObject *val)
302 {
303         if (prop->type  != IDP_GROUP) {
304                 PyErr_SetString( PyExc_TypeError, "unsubscriptable object");
305                 return -1;
306         }
307
308         if (val == NULL) { /* del idprop[key] */
309                 IDProperty *pkey = IDP_GetPropertyFromGroup(prop, _PyUnicode_AsString(key));
310                 if (pkey) {
311                         IDP_RemFromGroup(prop, pkey);
312                         IDP_FreeProperty(pkey);
313                         MEM_freeN(pkey);
314                         return 0;
315                 } else {
316                         PyErr_SetString( PyExc_KeyError, "property not found in group" );
317                         return -1;
318                 }
319         }
320         else {
321                 char *err;
322
323                 if (!PyUnicode_Check(key)) {
324                         PyErr_SetString( PyExc_TypeError, "only strings are allowed as subgroup keys" );
325                         return -1;
326                 }
327
328                 err = BPy_IDProperty_Map_ValidateAndCreate(_PyUnicode_AsString(key), prop, val);
329                 if (err) {
330                         PyErr_SetString( PyExc_KeyError, err );
331                         return -1;
332                 }
333
334                 return 0;
335         }
336 }
337
338 static int BPy_IDGroup_Map_SetItem(BPy_IDProperty *self, PyObject *key, PyObject *val)
339 {
340         return BPy_Wrap_SetMapItem(self->prop, key, val);
341 }
342
343 static PyObject *BPy_IDGroup_SpawnIterator(BPy_IDProperty *self)
344 {
345         BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &IDGroup_Iter_Type);
346         iter->group = self;
347         iter->mode = IDPROP_ITER_KEYS;
348         iter->cur = self->prop->data.group.first;
349         Py_XINCREF(iter);
350         return (PyObject*) iter;
351 }
352
353 static PyObject *BPy_IDGroup_MapDataToPy(IDProperty *prop)
354 {
355         switch (prop->type) {
356                 case IDP_STRING:
357                         return PyUnicode_FromString(prop->data.pointer);
358                         break;
359                 case IDP_FLOAT:
360                         return PyFloat_FromDouble(*((float*)&prop->data.val));
361                         break;
362                 case IDP_DOUBLE:
363                         return PyFloat_FromDouble(*((double*)&prop->data.val));
364                         break;
365                 case IDP_INT:
366                         return PyLong_FromSsize_t( prop->data.val );
367                         break;
368                 case IDP_ARRAY:
369                 {
370                         PyObject *seq = PyList_New(prop->len);
371                         int i;
372
373                         if (!seq) {
374                                 PyErr_SetString( PyExc_RuntimeError, "PyList_New() failed" );
375                                 return NULL;
376                         }
377
378                         for (i=0; i<prop->len; i++) {
379                                 if (prop->subtype == IDP_FLOAT) {
380                                         PyList_SET_ITEM(seq, i,
381                                                 PyFloat_FromDouble(((float*)prop->data.pointer)[i]));
382                                 } else if (prop->subtype == IDP_DOUBLE) {
383                                         PyList_SET_ITEM(seq, i,
384                                                 PyFloat_FromDouble(((double*)prop->data.pointer)[i]));
385                                 } else  {
386                                         PyList_SET_ITEM(seq, i,
387                                                   PyLong_FromLong(((int*)prop->data.pointer)[i]));
388                                 }
389                         }
390                         return seq;
391                 }
392                 case IDP_GROUP:
393                 {
394                         PyObject *dict = PyDict_New(), *wrap;
395                         IDProperty *loop;
396
397                         if (!dict) {
398                                 PyErr_SetString( PyExc_RuntimeError, "PyDict_New() failed" );
399                                 return NULL;
400                         }
401
402                         for (loop=prop->data.group.first; loop; loop=loop->next) {
403                                 wrap = BPy_IDGroup_MapDataToPy(loop);
404                                 if (!wrap) {
405                                         PyErr_SetString( PyExc_RuntimeError, "BPy_IDGroup_MapDataToPy() failed" );
406                                         return NULL;
407                                 }
408
409                                 PyDict_SetItemString(dict, loop->name, wrap);
410                         }
411                         return dict;
412                 }
413         }
414
415         PyErr_SetString( PyExc_RuntimeError, "eek!! a property exists with a bad type code!!!" );
416         return NULL;
417 }
418
419 static PyObject *BPy_IDGroup_Pop(BPy_IDProperty *self, PyObject *value)
420 {
421         IDProperty *idprop;
422         PyObject *pyform;
423         char *name = _PyUnicode_AsString(value);
424
425         if (!name) {
426                 PyErr_SetString( PyExc_TypeError, "pop expected at least 1 argument, got 0" );
427                 return NULL;
428         }
429
430         idprop= IDP_GetPropertyFromGroup(self->prop, name);
431
432         if(idprop) {
433                 pyform = BPy_IDGroup_MapDataToPy(idprop);
434
435                 if (!pyform) {
436                         /*ok something bad happened with the pyobject,
437                           so don't remove the prop from the group.  if pyform is
438                           NULL, then it already should have raised an exception.*/
439                           return NULL;
440                 }
441
442                 IDP_RemFromGroup(self->prop, idprop);
443                 return pyform;
444         }
445
446         PyErr_SetString( PyExc_KeyError, "item not in group" );
447         return NULL;
448 }
449
450 static PyObject *BPy_IDGroup_IterItems(BPy_IDProperty *self)
451 {
452         BPy_IDGroup_Iter *iter = PyObject_New(BPy_IDGroup_Iter, &IDGroup_Iter_Type);
453         iter->group = self;
454         iter->mode = IDPROP_ITER_ITEMS;
455         iter->cur = self->prop->data.group.first;
456         Py_XINCREF(iter);
457         return (PyObject*) iter;
458 }
459
460 /* utility function */
461 static void BPy_IDGroup_CorrectListLen(IDProperty *prop, PyObject *seq, int len)
462 {
463         int j;
464
465         printf("ID Property Error found and corrected in BPy_IDGroup_GetKeys/Values/Items!\n");
466
467         /*fill rest of list with valid references to None*/
468         for (j=len; j<prop->len; j++) {
469                 Py_INCREF(Py_None);
470                 PyList_SET_ITEM(seq, j, Py_None);
471         }
472
473         /*set correct group length*/
474         prop->len = len;
475 }
476
477 PyObject *BPy_Wrap_GetKeys(IDProperty *prop)
478 {
479         PyObject *seq = PyList_New(prop->len);
480         IDProperty *loop;
481         int i;
482
483         for (i=0, loop=prop->data.group.first; loop; loop=loop->next, i++)
484                 PyList_SET_ITEM(seq, i, PyUnicode_FromString(loop->name));
485
486         if (i != prop->len) {
487                 BPy_IDGroup_CorrectListLen(prop, seq, i);
488                 Py_DECREF(seq); /*free the list*/
489                 /*call self again*/
490                 return BPy_Wrap_GetKeys(prop);
491         }
492
493         return seq;
494 }
495
496 PyObject *BPy_Wrap_GetValues(ID *id, IDProperty *prop)
497 {
498         PyObject *seq = PyList_New(prop->len);
499         IDProperty *loop;
500         int i;
501
502         for (i=0, loop=prop->data.group.first; loop; loop=loop->next, i++) {
503                 PyList_SET_ITEM(seq, i, BPy_IDGroup_WrapData(id, loop));
504         }
505
506         if (i != prop->len) {
507                 BPy_IDGroup_CorrectListLen(prop, seq, i);
508                 Py_DECREF(seq); /*free the list*/
509                 /*call self again*/
510                 return BPy_Wrap_GetValues(id, prop);
511         }
512
513         return seq;
514 }
515
516 PyObject *BPy_Wrap_GetItems(ID *id, IDProperty *prop)
517 {
518         PyObject *seq = PyList_New(prop->len);
519         IDProperty *loop;
520         int i;
521
522         for (i=0, loop=prop->data.group.first; loop; loop=loop->next, i++) {
523                 PyObject *item= PyTuple_New(2);
524                 PyTuple_SET_ITEM(item, 0, PyUnicode_FromString(loop->name));
525                 PyTuple_SET_ITEM(item, 1, BPy_IDGroup_WrapData(id, loop));
526                 PyList_SET_ITEM(seq, i, item);
527         }
528
529         if (i != prop->len) {
530                 BPy_IDGroup_CorrectListLen(prop, seq, i);
531                 Py_DECREF(seq); /*free the list*/
532                 /*call self again*/
533                 return BPy_Wrap_GetItems(id, prop);
534         }
535
536         return seq;
537 }
538
539
540 static PyObject *BPy_IDGroup_GetKeys(BPy_IDProperty *self)
541 {
542         return BPy_Wrap_GetKeys(self->prop);
543 }
544
545 static PyObject *BPy_IDGroup_GetValues(BPy_IDProperty *self)
546 {
547         return BPy_Wrap_GetValues(self->id, self->prop);
548 }
549
550 static PyObject *BPy_IDGroup_GetItems(BPy_IDProperty *self)
551 {
552         return BPy_Wrap_GetItems(self->id, self->prop);
553 }
554
555 static int BPy_IDGroup_Contains(BPy_IDProperty *self, PyObject *value)
556 {
557         char *name = _PyUnicode_AsString(value);
558
559         if (!name) {
560                 PyErr_SetString( PyExc_TypeError, "expected a string");
561                 return -1;
562         }
563
564         return IDP_GetPropertyFromGroup(self->prop, name) ? 1:0;
565 }
566
567 static PyObject *BPy_IDGroup_Update(BPy_IDProperty *self, PyObject *value)
568 {
569         PyObject *pkey, *pval;
570         Py_ssize_t i=0;
571
572         if (!PyDict_Check(value)) {
573                 PyErr_SetString( PyExc_TypeError, "expected an object derived from dict.");
574                 return NULL;
575         }
576
577         while (PyDict_Next(value, &i, &pkey, &pval)) {
578                 BPy_IDGroup_Map_SetItem(self, pkey, pval);
579                 if (PyErr_Occurred()) return NULL;
580         }
581
582         Py_RETURN_NONE;
583 }
584
585 static PyObject *BPy_IDGroup_ConvertToPy(BPy_IDProperty *self)
586 {
587         return BPy_IDGroup_MapDataToPy(self->prop);
588 }
589
590
591 /* Matches python dict.get(key, [default]) */
592 PyObject* BPy_IDGroup_Get(BPy_IDProperty *self, PyObject *args)
593 {
594         IDProperty *idprop;
595         char *key;
596         PyObject* def = Py_None;
597
598         if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
599                 return NULL;
600
601         idprop= IDP_GetPropertyFromGroup(self->prop, key);
602         if (idprop) {
603                 PyObject* pyobj = BPy_IDGroup_WrapData(self->id, idprop);
604                 if (pyobj)
605                         return pyobj;
606         }
607
608         Py_INCREF(def);
609         return def;
610 }
611
612 static struct PyMethodDef BPy_IDGroup_methods[] = {
613         {"pop", (PyCFunction)BPy_IDGroup_Pop, METH_O,
614                 "pop an item from the group; raises KeyError if the item doesn't exist."},
615         {"iteritems", (PyCFunction)BPy_IDGroup_IterItems, METH_NOARGS,
616                 "iterate through the items in the dict; behaves like dictionary method iteritems."},
617         {"keys", (PyCFunction)BPy_IDGroup_GetKeys, METH_NOARGS,
618                 "get the keys associated with this group as a list of strings."},
619         {"values", (PyCFunction)BPy_IDGroup_GetValues, METH_NOARGS,
620                 "get the values associated with this group."},
621         {"items", (PyCFunction)BPy_IDGroup_GetItems, METH_NOARGS,
622                 "get the items associated with this group."},
623         {"update", (PyCFunction)BPy_IDGroup_Update, METH_O,
624                 "updates the values in the group with the values of another or a dict."},
625         {"get", (PyCFunction)BPy_IDGroup_Get, METH_VARARGS,
626                 "idprop.get(k[,d]) -> idprop[k] if k in idprop, else d.  d defaults to None."},
627         {"convert_to_pyobject", (PyCFunction)BPy_IDGroup_ConvertToPy, METH_NOARGS,
628                 "return a purely python version of the group."},
629         {0, NULL, 0, NULL}
630 };
631
632 static PySequenceMethods BPy_IDGroup_Seq = {
633         (lenfunc) BPy_IDGroup_Map_Len,                  /* lenfunc sq_length */
634         0,                                                                      /* binaryfunc sq_concat */
635         0,                                                                      /* ssizeargfunc sq_repeat */
636         0,                                                                      /* ssizeargfunc sq_item */ /* TODO - setting this will allow PySequence_Check to return True */
637         0,                                                                      /* intintargfunc ***was_sq_slice*** */
638         0,                                                                      /* intobjargproc sq_ass_item */
639         0,                                                                      /* ssizeobjargproc ***was_sq_ass_slice*** */
640         (objobjproc) BPy_IDGroup_Contains,      /* objobjproc sq_contains */
641         0,                                                                      /* binaryfunc sq_inplace_concat */
642         0,                                                                      /* ssizeargfunc sq_inplace_repeat */
643 };
644
645 PyMappingMethods BPy_IDGroup_Mapping = {
646         (lenfunc)BPy_IDGroup_Map_Len,                   /*inquiry mp_length */
647         (binaryfunc)BPy_IDGroup_Map_GetItem,            /*binaryfunc mp_subscript */
648         (objobjargproc)BPy_IDGroup_Map_SetItem, /*objobjargproc mp_ass_subscript */
649 };
650
651 PyTypeObject IDGroup_Type = {
652         PyVarObject_HEAD_INIT(NULL, 0)
653         /*  For printing, in format "<module>.<name>" */
654         "Blender IDProperty",           /* char *tp_name; */
655         sizeof( BPy_IDProperty ),       /* int tp_basicsize; */
656         0,                          /* tp_itemsize;  For allocation */
657
658         /* Methods to implement standard operations */
659
660         NULL,                                           /* destructor tp_dealloc; */
661         NULL,                       /* printfunc tp_print; */
662         NULL,     /* getattrfunc tp_getattr; */
663         NULL,     /* setattrfunc tp_setattr; */
664         NULL,                       /* cmpfunc tp_compare; */
665         ( reprfunc ) IDGroup_repr,     /* reprfunc tp_repr; */
666
667         /* Method suites for standard classes */
668
669         NULL,                       /* PyNumberMethods *tp_as_number; */
670         &BPy_IDGroup_Seq,                       /* PySequenceMethods *tp_as_sequence; */
671         &BPy_IDGroup_Mapping,           /* PyMappingMethods *tp_as_mapping; */
672
673         /* More standard operations (here for binary compatibility) */
674
675         NULL,                       /* hashfunc tp_hash; */
676         NULL,                       /* ternaryfunc tp_call; */
677         NULL,                       /* reprfunc tp_str; */
678         NULL,                       /* getattrofunc tp_getattro; */
679         NULL,                       /* setattrofunc tp_setattro; */
680
681         /* Functions to access object as input/output buffer */
682         NULL,                       /* PyBufferProcs *tp_as_buffer; */
683
684   /*** Flags to define presence of optional/expanded features ***/
685         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
686
687         NULL,                       /*  char *tp_doc;  Documentation string */
688   /*** Assigned meaning in release 2.0 ***/
689         /* call function for all accessible objects */
690         NULL,                       /* traverseproc tp_traverse; */
691
692         /* delete references to contained objects */
693         NULL,                       /* inquiry tp_clear; */
694
695   /***  Assigned meaning in release 2.1 ***/
696   /*** rich comparisons ***/
697         NULL,                       /* richcmpfunc tp_richcompare; */
698
699   /***  weak reference enabler ***/
700         0,                          /* long tp_weaklistoffset; */
701
702   /*** Added in release 2.2 ***/
703         /*   Iterators */
704         (getiterfunc)BPy_IDGroup_SpawnIterator, /* getiterfunc tp_iter; */
705         NULL,                       /* iternextfunc tp_iternext; */
706   /*** Attribute descriptor and subclassing stuff ***/
707         BPy_IDGroup_methods,        /* struct PyMethodDef *tp_methods; */
708         NULL,                       /* struct PyMemberDef *tp_members; */
709         BPy_IDGroup_getseters,       /* struct PyGetSetDef *tp_getset; */
710 };
711
712 /*********** Main external wrapping function *******/
713 PyObject *BPy_Wrap_IDProperty(ID *id, IDProperty *prop, IDProperty *parent)
714 {
715         BPy_IDProperty *wrap = PyObject_New(BPy_IDProperty, &IDGroup_Type);
716         wrap->prop = prop;
717         wrap->parent = parent;
718         wrap->id = id;
719         //wrap->destroy = 0;
720         return (PyObject*) wrap;
721 }
722
723
724 /********Array Wrapper********/
725
726 static PyObject *IDArray_repr(BPy_IDArray *self)
727 {
728         return PyUnicode_FromString("(ID Array)");
729 }
730
731
732 static PyObject *BPy_IDArray_GetType(BPy_IDArray *self)
733 {
734         return PyLong_FromSsize_t( self->prop->subtype );
735 }
736
737 static PyObject *BPy_IDArray_GetLen(BPy_IDArray *self)
738 {
739         return PyLong_FromSsize_t( self->prop->len );
740 }
741
742 static PyGetSetDef BPy_IDArray_getseters[] = {
743         {"len",
744          (getter)BPy_IDArray_GetLen, (setter)NULL,
745          "The length of the array, can also be gotten with len(array).",
746          NULL},
747         {"type",
748          (getter)BPy_IDArray_GetType, (setter)NULL,
749          "The type of the data in the array, is an ant.",
750          NULL},
751         {NULL, NULL, NULL, NULL, NULL},
752 };
753
754 static PyObject *BPy_IDArray_ConvertToPy(BPy_IDArray *self)
755 {
756         return BPy_IDGroup_MapDataToPy(self->prop);
757 }
758
759 static PyMethodDef BPy_IDArray_methods[] = {
760         {"convert_to_pyobject", (PyCFunction)BPy_IDArray_ConvertToPy, METH_NOARGS,
761                 "return a purely python version of the group."},
762         {0, NULL, 0, NULL}
763 };
764
765 static int BPy_IDArray_Len(BPy_IDArray *self)
766 {
767         return self->prop->len;
768 }
769
770 static PyObject *BPy_IDArray_GetItem(BPy_IDArray *self, int index)
771 {
772         if (index < 0 || index >= self->prop->len) {
773                 PyErr_SetString( PyExc_IndexError, "index out of range!");
774                 return NULL;
775         }
776
777         switch (self->prop->subtype) {
778                 case IDP_FLOAT:
779                         return PyFloat_FromDouble( (double)(((float*)self->prop->data.pointer)[index]));
780                         break;
781                 case IDP_DOUBLE:
782                         return PyFloat_FromDouble( (((double*)self->prop->data.pointer)[index]));
783                         break;
784                 case IDP_INT:
785                         return PyLong_FromLong( (long)((int*)self->prop->data.pointer)[index] );
786                         break;
787         }
788
789         PyErr_SetString( PyExc_RuntimeError, "invalid/corrupt array type!");
790         return NULL;
791 }
792
793 static int BPy_IDArray_SetItem(BPy_IDArray *self, int index, PyObject *value)
794 {
795         int i;
796         float f;
797         double d;
798
799         if (index < 0 || index >= self->prop->len) {
800                 PyErr_SetString( PyExc_RuntimeError, "index out of range!");
801                 return -1;
802         }
803
804         switch (self->prop->subtype) {
805                 case IDP_FLOAT:
806                         f= (float)PyFloat_AsDouble(value);
807                         if (f==-1 && PyErr_Occurred()) {
808                                 PyErr_SetString(PyExc_TypeError, "expected a float");
809                                 return -1;
810                         }
811                         ((float*)self->prop->data.pointer)[index] = f;
812                         break;
813                 case IDP_DOUBLE:
814                         d= PyFloat_AsDouble(value);
815                         if (d==-1 && PyErr_Occurred()) {
816                                 PyErr_SetString(PyExc_TypeError, "expected a float");
817                                 return -1;
818                         }
819                         ((double*)self->prop->data.pointer)[index] = d;
820                         break;
821                 case IDP_INT:
822                         i= PyLong_AsSsize_t(value);
823                         if (i==-1 && PyErr_Occurred()) {
824                                 PyErr_SetString(PyExc_TypeError, "expected an int type");
825                                 return -1;
826                         }
827
828                         ((int*)self->prop->data.pointer)[index] = i;
829                         break;
830         }
831         return 0;
832 }
833
834 static PySequenceMethods BPy_IDArray_Seq = {
835         (lenfunc) BPy_IDArray_Len,                      /* inquiry sq_length */
836         0,                                                                      /* binaryfunc sq_concat */
837         0,                                                                      /* intargfunc sq_repeat */
838         (ssizeargfunc)BPy_IDArray_GetItem,      /* intargfunc sq_item */
839         0,                                                                      /* intintargfunc sq_slice */
840         (ssizeobjargproc)BPy_IDArray_SetItem,   /* intobjargproc sq_ass_item */
841         0,                                                                      /* intintobjargproc sq_ass_slice */
842         0,                                                                      /* objobjproc sq_contains */
843                                 /* Added in release 2.0 */
844         0,                                                                      /* binaryfunc sq_inplace_concat */
845         0,                                                                      /* intargfunc sq_inplace_repeat */
846 };
847
848 PyTypeObject IDArray_Type = {
849         PyVarObject_HEAD_INIT(NULL, 0)
850         /*  For printing, in format "<module>.<name>" */
851         "Blender IDArray",           /* char *tp_name; */
852         sizeof( BPy_IDArray ),       /* int tp_basicsize; */
853         0,                          /* tp_itemsize;  For allocation */
854
855         /* Methods to implement standard operations */
856
857         NULL,                                           /* destructor tp_dealloc; */
858         NULL,                       /* printfunc tp_print; */
859         NULL,     /* getattrfunc tp_getattr; */
860         NULL,     /* setattrfunc tp_setattr; */
861         NULL,                       /* cmpfunc tp_compare; */
862         ( reprfunc ) IDArray_repr,     /* reprfunc tp_repr; */
863
864         /* Method suites for standard classes */
865
866         NULL,                       /* PyNumberMethods *tp_as_number; */
867         &BPy_IDArray_Seq,                       /* PySequenceMethods *tp_as_sequence; */
868         NULL,                       /* PyMappingMethods *tp_as_mapping; */
869
870         /* More standard operations (here for binary compatibility) */
871
872         NULL,                       /* hashfunc tp_hash; */
873         NULL,                       /* ternaryfunc tp_call; */
874         NULL,                       /* reprfunc tp_str; */
875         NULL,                       /* getattrofunc tp_getattro; */
876         NULL,                       /* setattrofunc tp_setattro; */
877
878         /* Functions to access object as input/output buffer */
879         NULL,                       /* PyBufferProcs *tp_as_buffer; */
880
881   /*** Flags to define presence of optional/expanded features ***/
882         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
883
884         NULL,                       /*  char *tp_doc;  Documentation string */
885   /*** Assigned meaning in release 2.0 ***/
886         /* call function for all accessible objects */
887         NULL,                       /* traverseproc tp_traverse; */
888
889         /* delete references to contained objects */
890         NULL,                       /* inquiry tp_clear; */
891
892   /***  Assigned meaning in release 2.1 ***/
893   /*** rich comparisons ***/
894         NULL,                       /* richcmpfunc tp_richcompare; */
895
896   /***  weak reference enabler ***/
897         0,                          /* long tp_weaklistoffset; */
898
899   /*** Added in release 2.2 ***/
900         /*   Iterators */
901         NULL,                       /* getiterfunc tp_iter; */
902         NULL,                       /* iternextfunc tp_iternext; */
903
904   /*** Attribute descriptor and subclassing stuff ***/
905         BPy_IDArray_methods,            /* struct PyMethodDef *tp_methods; */
906         NULL,                       /* struct PyMemberDef *tp_members; */
907         BPy_IDArray_getseters,       /* struct PyGetSetDef *tp_getset; */
908         NULL,                       /* struct _typeobject *tp_base; */
909         NULL,                       /* PyObject *tp_dict; */
910         NULL,                       /* descrgetfunc tp_descr_get; */
911         NULL,                       /* descrsetfunc tp_descr_set; */
912         0,                          /* long tp_dictoffset; */
913         NULL,                       /* initproc tp_init; */
914         NULL,                       /* allocfunc tp_alloc; */
915         NULL,                       /* newfunc tp_new; */
916         /*  Low-level free-memory routine */
917         NULL,                       /* freefunc tp_free;  */
918         /* For PyObject_IS_GC */
919         NULL,                       /* inquiry tp_is_gc;  */
920         NULL,                       /* PyObject *tp_bases; */
921         /* method resolution order */
922         NULL,                       /* PyObject *tp_mro;  */
923         NULL,                       /* PyObject *tp_cache; */
924         NULL,                       /* PyObject *tp_subclasses; */
925         NULL,                       /* PyObject *tp_weaklist; */
926         NULL
927 };
928
929 /*********** ID Property Group iterator ********/
930
931 static PyObject *IDGroup_Iter_iterself(PyObject *self)
932 {
933         Py_XINCREF(self);
934         return self;
935 }
936
937 static PyObject *IDGroup_Iter_repr(BPy_IDGroup_Iter *self)
938 {
939         return PyUnicode_FromString("(ID Property Group)");
940 }
941
942 static PyObject *BPy_Group_Iter_Next(BPy_IDGroup_Iter *self)
943 {
944         IDProperty *cur=NULL;
945         PyObject *ret;
946
947         if (self->cur) {
948                 cur = self->cur;
949                 self->cur = self->cur->next;
950                 if (self->mode == IDPROP_ITER_ITEMS) {
951                         ret = PyTuple_New(2);
952                         PyTuple_SET_ITEM(ret, 0, PyUnicode_FromString(cur->name));
953                         PyTuple_SET_ITEM(ret, 1, BPy_IDGroup_WrapData(self->group->id, cur));
954                         return ret;
955                 } else {
956                         return PyUnicode_FromString(cur->name);
957                 }
958         } else {
959                 PyErr_SetString( PyExc_StopIteration, "iterator at end" );
960                 return NULL;
961         }
962 }
963
964 PyTypeObject IDGroup_Iter_Type = {
965         PyVarObject_HEAD_INIT(NULL, 0)
966         /*  For printing, in format "<module>.<name>" */
967         "Blender IDGroup_Iter",           /* char *tp_name; */
968         sizeof( BPy_IDGroup_Iter ),       /* int tp_basicsize; */
969         0,                          /* tp_itemsize;  For allocation */
970
971         /* Methods to implement standard operations */
972
973         NULL,                                           /* destructor tp_dealloc; */
974         NULL,                       /* printfunc tp_print; */
975         NULL,     /* getattrfunc tp_getattr; */
976         NULL,     /* setattrfunc tp_setattr; */
977         NULL,                       /* cmpfunc tp_compare; */
978         ( reprfunc ) IDGroup_Iter_repr,     /* reprfunc tp_repr; */
979
980         /* Method suites for standard classes */
981
982         NULL,                       /* PyNumberMethods *tp_as_number; */
983         NULL,                                           /* PySequenceMethods *tp_as_sequence; */
984         NULL,                       /* PyMappingMethods *tp_as_mapping; */
985
986         /* More standard operations (here for binary compatibility) */
987
988         NULL,                       /* hashfunc tp_hash; */
989         NULL,                       /* ternaryfunc tp_call; */
990         NULL,                       /* reprfunc tp_str; */
991         NULL,                       /* getattrofunc tp_getattro; */
992         NULL,                       /* setattrofunc tp_setattro; */
993
994         /* Functions to access object as input/output buffer */
995         NULL,                       /* PyBufferProcs *tp_as_buffer; */
996
997   /*** Flags to define presence of optional/expanded features ***/
998         Py_TPFLAGS_DEFAULT,         /* long tp_flags; */
999
1000         NULL,                       /*  char *tp_doc;  Documentation string */
1001   /*** Assigned meaning in release 2.0 ***/
1002         /* call function for all accessible objects */
1003         NULL,                       /* traverseproc tp_traverse; */
1004
1005         /* delete references to contained objects */
1006         NULL,                       /* inquiry tp_clear; */
1007
1008   /***  Assigned meaning in release 2.1 ***/
1009   /*** rich comparisons ***/
1010         NULL,                       /* richcmpfunc tp_richcompare; */
1011
1012   /***  weak reference enabler ***/
1013         0,                          /* long tp_weaklistoffset; */
1014
1015   /*** Added in release 2.2 ***/
1016         /*   Iterators */
1017         IDGroup_Iter_iterself,              /* getiterfunc tp_iter; */
1018         (iternextfunc) BPy_Group_Iter_Next, /* iternextfunc tp_iternext; */
1019 };
1020
1021 void IDProp_Init_Types(void)
1022 {
1023         PyType_Ready( &IDGroup_Type );
1024         PyType_Ready( &IDGroup_Iter_Type );
1025         PyType_Ready( &IDArray_Type );
1026 }