support for object data material assignment in python
authorCampbell Barton <ideasman42@gmail.com>
Sat, 1 Oct 2011 17:54:33 +0000 (17:54 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Sat, 1 Oct 2011 17:54:33 +0000 (17:54 +0000)
eg:
 bpy.context.object.data.materials[0] = bpy.data.materials["SomeMaterial"]

source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/rna_ID.c
source/blender/makesrna/intern/rna_access.c
source/blender/makesrna/intern/rna_curve.c
source/blender/makesrna/intern/rna_internal.h
source/blender/makesrna/intern/rna_internal_types.h
source/blender/makesrna/intern/rna_mesh.c
source/blender/makesrna/intern/rna_meta.c
source/blender/python/intern/bpy_rna.c

index 6dbc002d5057119a11d810df4c9ad24db70229ae..1e9496fdbbb3e82daf97389fc2b1ad6b819aa04a 100644 (file)
@@ -778,7 +778,7 @@ int RNA_property_collection_length(PointerRNA *ptr, PropertyRNA *prop);
 int RNA_property_collection_lookup_index(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *t_ptr);
 int RNA_property_collection_lookup_int(PointerRNA *ptr, PropertyRNA *prop, int key, PointerRNA *r_ptr);
 int RNA_property_collection_lookup_string(PointerRNA *ptr, PropertyRNA *prop, const char *key, PointerRNA *r_ptr);
-int RNA_property_collection_assign_int(PointerRNA *ptr, PropertyRNA *prop, const int key, PointerRNA *assign_ptr);
+int RNA_property_collection_assign_int(PointerRNA *ptr, PropertyRNA *prop, const int key, const PointerRNA *assign_ptr);
 int RNA_property_collection_type_get(PointerRNA *ptr, PropertyRNA *prop, PointerRNA *r_ptr);
 
 /* efficient functions to set properties for arrays */
index 492f51967b2f7617171e1843f293f7e671af3feb..3f8a310285e33c75d0b837e9761473fcd11d295a 100644 (file)
@@ -314,6 +314,14 @@ static int rna_IDPArray_length(PointerRNA *ptr)
        return prop->len;
 }
 
+int rna_IDMaterials_assign_int(PointerRNA *ptr, int key, PointerRNA *assign_ptr)
+{
+       ID *id=           ptr->id.data;
+       Material *mat_id= assign_ptr->id.data;
+       assign_material_id(id, mat_id, key + 1);
+       return 1;
+}
+
 #else
 
 static void rna_def_ID_properties(BlenderRNA *brna)
index c6a9627aa3c7c87dc1ace396f3c6a143d342540b..24e1aa078cf4a02a686a1f97a656040997cfc603 100644 (file)
@@ -1095,6 +1095,9 @@ StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop)
                if(cprop->item_type)
                        return cprop->item_type;
        }
+       else {
+               BLI_assert(0);
+       }
 
        return &RNA_UnknownType;
 }
@@ -2865,7 +2868,7 @@ int RNA_property_collection_lookup_string(PointerRNA *ptr, PropertyRNA *prop, co
 }
 
 /* zero return is an assignment error */
-int RNA_property_collection_assign_int(PointerRNA *ptr, PropertyRNA *prop, const int key, PointerRNA *assign_ptr)
+int RNA_property_collection_assign_int(PointerRNA *ptr, PropertyRNA *prop, const int key, const PointerRNA *assign_ptr)
 {
        CollectionPropertyRNA *cprop= (CollectionPropertyRNA*)rna_ensure_property(prop);
 
index 28c1a3bc2349b1339485660bd46ec129d4fe7a4b..edae977f3f62d8665830eba1287b9dc20e17d9ac 100644 (file)
@@ -1428,7 +1428,8 @@ static void rna_def_curve(BlenderRNA *brna)
        RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol");
        RNA_def_property_struct_type(prop, "Material");
        RNA_def_property_ui_text(prop, "Materials", "");
-       RNA_def_property_srna(prop, "IDMaterials"); /* see rna_ID.c */  
+       RNA_def_property_srna(prop, "IDMaterials"); /* see rna_ID.c */
+       RNA_def_property_collection_funcs(prop, 0, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int");
 }
 
 static void rna_def_curve_nurb(BlenderRNA *brna)
index cf1be39124ee1be42b50baf053198dd20cf3e2c0..aab74056ad9367de3589f4946ffbf17e33f333a8 100644 (file)
@@ -382,6 +382,9 @@ struct MTex *rna_mtex_texture_slots_add(struct ID *self, struct bContext *C, str
 struct MTex *rna_mtex_texture_slots_create(struct ID *self, struct bContext *C, struct ReportList *reports, int index);
 void rna_mtex_texture_slots_clear(struct ID *self, struct bContext *C, struct ReportList *reports, int index);
 
+
+int rna_IDMaterials_assign_int(struct PointerRNA *ptr, int key, struct PointerRNA *assign_ptr);
+
 #endif /* RNA_INTERNAL_H */
 
 
index 87b35459d40a76fbd7328e0f66e86ab085ae4f01..50790a0077f707c821071c6eb0a844c8afcc19ab 100644 (file)
@@ -102,7 +102,7 @@ typedef PointerRNA (*PropCollectionGetFunc)(struct CollectionPropertyIterator *i
 typedef int (*PropCollectionLengthFunc)(struct PointerRNA *ptr);
 typedef int (*PropCollectionLookupIntFunc)(struct PointerRNA *ptr, int key, struct PointerRNA *r_ptr);
 typedef int (*PropCollectionLookupStringFunc)(struct PointerRNA *ptr, const char *key, struct PointerRNA *r_ptr);
-typedef int (*PropCollectionAssignIntFunc)(struct PointerRNA *ptr, int key, struct PointerRNA *assign_ptr);
+typedef int (*PropCollectionAssignIntFunc)(struct PointerRNA *ptr, int key, const struct PointerRNA *assign_ptr);
 
 /* Container - generic abstracted container of RNA properties */
 typedef struct ContainerRNA {
index 44be5ae8e35f5ba3766b82daf42d7014dde68c74..ad4467a6d0b190b8b7469ab76c22a76153855448 100644 (file)
@@ -1942,6 +1942,7 @@ static void rna_def_mesh(BlenderRNA *brna)
        RNA_def_property_struct_type(prop, "Material");
        RNA_def_property_ui_text(prop, "Materials", "");
        RNA_def_property_srna(prop, "IDMaterials"); /* see rna_ID.c */
+       RNA_def_property_collection_funcs(prop, 0, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int");
 
        /* Mesh Draw Options for Edit Mode*/
        
index 5e5cf0be0aebaaa3f438c8be57bc189df90728d9..1c7359cc195c48672b1a554ed55eff8aebc9ffdd 100644 (file)
@@ -330,7 +330,8 @@ static void rna_def_metaball(BlenderRNA *brna)
        RNA_def_property_collection_sdna(prop, NULL, "mat", "totcol");
        RNA_def_property_struct_type(prop, "Material");
        RNA_def_property_ui_text(prop, "Materials", "");
-       RNA_def_property_srna(prop, "IDMaterials"); /* see rna_ID.c */  
+       RNA_def_property_srna(prop, "IDMaterials"); /* see rna_ID.c */
+       RNA_def_property_collection_funcs(prop, 0, NULL, NULL, NULL, NULL, NULL, NULL, "rna_IDMaterials_assign_int");
        
        /* anim */
        rna_def_animdata_common(srna);
index d367ea92cf4d2f46316381037770f91f3bc45303..d5a950fc5bbeb2678c314de02ae62af08abdb6a8 100644 (file)
@@ -1922,6 +1922,21 @@ static int pyrna_prop_collection_bool(BPy_PropertyRNA *self)
        return test;
 }
 
+
+#define PYRNA_PROP_COLLECTION_ABS_INDEX(ret_err)                              \
+       /* notice getting the length of the collection is avoided unless negative \
+        * index is used or to detect internal error with a valid index.          \
+        * This is done for faster lookups. */                                    \
+       if(keynum < 0) {                                                          \
+               keynum_abs += RNA_property_collection_length(&self->ptr, self->prop); \
+               if(keynum_abs < 0) {                                                  \
+                       PyErr_Format(PyExc_IndexError,                                    \
+                                    "bpy_prop_collection[%d]: out of range.", keynum);   \
+                       return ret_err;                                                   \
+               }                                                                     \
+       }                                                                         \
+
+
 /* internal use only */
 static PyObject *pyrna_prop_collection_subscript_int(BPy_PropertyRNA *self, Py_ssize_t keynum)
 {
@@ -1930,17 +1945,7 @@ static PyObject *pyrna_prop_collection_subscript_int(BPy_PropertyRNA *self, Py_s
 
        PYRNA_PROP_CHECK_OBJ(self)
 
-       /* notice getting the length of the collection is avoided unless negative index is used
-        * or to detect internal error with a valid index.
-        * This is done for faster lookups. */
-       if(keynum < 0) {
-               keynum_abs += RNA_property_collection_length(&self->ptr, self->prop);
-
-               if(keynum_abs < 0) {
-                       PyErr_Format(PyExc_IndexError, "bpy_prop_collection[%d]: out of range.", keynum);
-                       return NULL;
-               }
-       }
+       PYRNA_PROP_COLLECTION_ABS_INDEX(NULL);
 
        if(RNA_property_collection_lookup_int(&self->ptr, self->prop, keynum_abs, &newptr)) {
                return pyrna_struct_CreatePyObject(&newptr);
@@ -1963,6 +1968,28 @@ static PyObject *pyrna_prop_collection_subscript_int(BPy_PropertyRNA *self, Py_s
        }
 }
 
+/* values type must have been already checked */
+static int pyrna_prop_collection_ass_subscript_int(BPy_PropertyRNA *self, Py_ssize_t keynum, PyObject *value)
+{
+       Py_ssize_t keynum_abs= keynum;
+       const PointerRNA *ptr= (value == Py_None) ? (&PointerRNA_NULL) : &((BPy_StructRNA *)value)->ptr;
+
+       PYRNA_PROP_CHECK_INT(self)
+
+       PYRNA_PROP_COLLECTION_ABS_INDEX(-1);
+
+       if(RNA_property_collection_assign_int(&self->ptr, self->prop, keynum_abs, ptr) == 0) {
+
+               PyErr_Format(PyExc_IndexError,
+                            "bpy_prop_collection[index] = value: "
+                            "failed assignment (unknown reason)", keynum);
+
+               return -1;
+       }
+
+       return 0;
+}
+
 static PyObject *pyrna_prop_array_subscript_int(BPy_PropertyArrayRNA *self, int keynum)
 {
        int len;
@@ -2173,6 +2200,128 @@ static PyObject *pyrna_prop_collection_subscript(BPy_PropertyRNA *self, PyObject
        }
 }
 
+/* generic check to see if a PyObject is compatible with a collection
+ * -1 on failier, 0 on success, sets the error */
+static int pyrna_prop_collection_type_check(BPy_PropertyRNA *self, PyObject *value)
+{
+       StructRNA *prop_srna;
+
+       if(value == Py_None) {
+               if (RNA_property_flag(self->prop) & PROP_NEVER_NULL) {
+                       PyErr_Format(PyExc_TypeError,
+                                                "bpy_prop_collection[key] = value: invalid, "
+                                                "this collection doesnt support None assignment");
+                       return -1;
+               }
+               else {
+                       return 0; /* None is OK */
+               }
+       }
+       else if (BPy_StructRNA_Check(value) == 0) {
+               PyErr_Format(PyExc_TypeError,
+                            "bpy_prop_collection[key] = value: invalid, "
+                            "expected a StructRNA type or None, not a %.200s",
+                            Py_TYPE(value)->tp_name);
+               return -1;
+       }
+       else if((prop_srna= RNA_property_pointer_type(&self->ptr, self->prop))) {
+               StructRNA *value_srna= ((BPy_StructRNA *)value)->ptr.type;
+               if (RNA_struct_is_a(value_srna, prop_srna) == 0) {
+                       PyErr_Format(PyExc_TypeError,
+                                    "bpy_prop_collection[key] = value: invalid, "
+                                    "expected a '%.200s' type or None, not a '%.200s'",
+                                    RNA_struct_identifier(prop_srna),
+                                    RNA_struct_identifier(value_srna)
+                                    );
+                       return -1;
+               }
+               else {
+                       return 0; /* OK, this is the correct type!*/
+               }
+       }
+
+       PyErr_Format(PyExc_TypeError,
+                    "bpy_prop_collection[key] = value: internal error, "
+                    "failed to get the collection type");
+       return -1;
+}
+
+/* note: currently this is a copy of 'pyrna_prop_collection_subscript' with
+ * large blocks commented, we may support slice/key indicies later */
+static int pyrna_prop_collection_ass_subscript(BPy_PropertyRNA *self, PyObject *key, PyObject *value)
+{
+       PYRNA_PROP_CHECK_INT(self);
+
+       /* validate the assigned value */
+       if(value == NULL) {
+               PyErr_SetString(PyExc_TypeError,
+                               "del bpy_prop_collection[key]: not supported");
+               return -1;
+       }
+       else if (pyrna_prop_collection_type_check(self, value) == -1) {
+               return -1; /* exception is set */
+       }
+
+#if 0
+       if (PyUnicode_Check(key)) {
+               return pyrna_prop_collection_subscript_str(self, _PyUnicode_AsString(key));
+       }
+       else
+#endif
+       if (PyIndex_Check(key)) {
+               Py_ssize_t i= PyNumber_AsSsize_t(key, PyExc_IndexError);
+               if (i == -1 && PyErr_Occurred())
+                       return -1;
+
+               return pyrna_prop_collection_ass_subscript_int(self, i, value);
+       }
+#if 0 /* TODO, fake slice assignment */
+       else if (PySlice_Check(key)) {
+               PySliceObject *key_slice= (PySliceObject *)key;
+               Py_ssize_t step= 1;
+
+               if(key_slice->step != Py_None && !_PyEval_SliceIndex(key, &step)) {
+                       return NULL;
+               }
+               else if (step != 1) {
+                       PyErr_SetString(PyExc_TypeError, "bpy_prop_collection[slice]: slice steps not supported");
+                       return NULL;
+               }
+               else if(key_slice->start == Py_None && key_slice->stop == Py_None) {
+                       return pyrna_prop_collection_subscript_slice(self, 0, PY_SSIZE_T_MAX);
+               }
+               else {
+                       Py_ssize_t start= 0, stop= PY_SSIZE_T_MAX;
+
+                       /* avoid PySlice_GetIndicesEx because it needs to know the length ahead of time. */
+                       if(key_slice->start != Py_None && !_PyEval_SliceIndex(key_slice->start, &start))        return NULL;
+                       if(key_slice->stop != Py_None && !_PyEval_SliceIndex(key_slice->stop, &stop))           return NULL;
+
+                       if(start < 0 || stop < 0) {
+                               /* only get the length for negative values */
+                               Py_ssize_t len= (Py_ssize_t)RNA_property_collection_length(&self->ptr, self->prop);
+                               if(start < 0) start += len;
+                               if(stop < 0) start += len;
+                       }
+
+                       if (stop - start <= 0) {
+                               return PyList_New(0);
+                       }
+                       else {
+                               return pyrna_prop_collection_subscript_slice(self, start, stop);
+                       }
+               }
+       }
+#endif
+       else {
+               PyErr_Format(PyExc_TypeError,
+                            "bpy_prop_collection[key]: invalid key, "
+                            "must be a string or an int, not %.200s",
+                            Py_TYPE(key)->tp_name);
+               return -1;
+       }
+}
+
 static PyObject *pyrna_prop_array_subscript(BPy_PropertyArrayRNA *self, PyObject *key)
 {
        PYRNA_PROP_CHECK_OBJ((BPy_PropertyRNA *)self)
@@ -2409,7 +2558,7 @@ static PyMappingMethods pyrna_prop_array_as_mapping= {
 static PyMappingMethods pyrna_prop_collection_as_mapping= {
        (lenfunc) pyrna_prop_collection_length, /* mp_length */
        (binaryfunc) pyrna_prop_collection_subscript,   /* mp_subscript */
-       (objobjargproc) NULL,   /* mp_ass_subscript */
+       (objobjargproc) pyrna_prop_collection_ass_subscript,    /* mp_ass_subscript */
 };
 
 /* only for fast bool's, large structs, assign nb_bool on init */
@@ -2505,7 +2654,7 @@ static PySequenceMethods pyrna_prop_collection_as_sequence= {
        NULL,           /* sq_repeat */
        (ssizeargfunc)pyrna_prop_collection_subscript_int, /* sq_item */ /* Only set this so PySequence_Check() returns True */
        NULL,           /* *was* sq_slice */
-       NULL,           /* sq_ass_item */
+       (ssizeobjargproc)/* pyrna_prop_collection_ass_subscript_int */ NULL /* let mapping take this one */, /* sq_ass_item */
        NULL,           /* *was* sq_ass_slice */
        (objobjproc)pyrna_prop_collection_contains,     /* sq_contains */
        (binaryfunc) NULL, /* sq_inplace_concat */