Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * Contributor(s): Campbell Barton 00019 * 00020 * ***** END GPL LICENSE BLOCK ***** 00021 */ 00022 00029 #include <Python.h> 00030 #include <float.h> /* FLT_MIN/MAX */ 00031 00032 #include "MEM_guardedalloc.h" 00033 00034 #include "BLI_string.h" 00035 00036 #include "DNA_scene_types.h" 00037 #include "DNA_anim_types.h" 00038 #include "ED_keyframing.h" 00039 00040 #include "BKE_report.h" 00041 #include "BKE_context.h" 00042 #include "BKE_animsys.h" 00043 #include "BKE_fcurve.h" 00044 00045 #include "RNA_access.h" 00046 00047 #include "WM_api.h" 00048 #include "WM_types.h" 00049 00050 #include "bpy_rna.h" 00051 #include "bpy_util.h" 00052 #include "bpy_rna_anim.h" 00053 00054 #define TRUE 1 00055 #define FALSE 0 00056 00057 /* for keyframes and drivers */ 00058 static int pyrna_struct_anim_args_parse( 00059 PointerRNA *ptr, const char *error_prefix, const char *path, 00060 const char **path_full, int *index) 00061 { 00062 const int is_idbase = RNA_struct_is_ID(ptr->type); 00063 PropertyRNA *prop; 00064 PointerRNA r_ptr; 00065 00066 if (ptr->data == NULL) { 00067 PyErr_Format(PyExc_TypeError, 00068 "%.200s this struct has no data, can't be animated", 00069 error_prefix); 00070 return -1; 00071 } 00072 00073 /* full paths can only be given from ID base */ 00074 if (is_idbase) { 00075 int r_index = -1; 00076 if (RNA_path_resolve_full(ptr, path, &r_ptr, &prop, &r_index) == 0) { 00077 prop = NULL; 00078 } 00079 else if (r_index != -1) { 00080 PyErr_Format(PyExc_ValueError, 00081 "%.200s path includes index, must be a separate argument", 00082 error_prefix, path); 00083 return -1; 00084 } 00085 else if (ptr->id.data != r_ptr.id.data) { 00086 PyErr_Format(PyExc_ValueError, 00087 "%.200s path spans ID blocks", 00088 error_prefix, path); 00089 return -1; 00090 } 00091 } 00092 else { 00093 prop = RNA_struct_find_property(ptr, path); 00094 r_ptr = *ptr; 00095 } 00096 00097 if (prop == NULL) { 00098 PyErr_Format(PyExc_TypeError, 00099 "%.200s property \"%s\" not found", 00100 error_prefix, path); 00101 return -1; 00102 } 00103 00104 if (!RNA_property_animateable(&r_ptr, prop)) { 00105 PyErr_Format(PyExc_TypeError, 00106 "%.200s property \"%s\" not animatable", 00107 error_prefix, path); 00108 return -1; 00109 } 00110 00111 if (RNA_property_array_check(prop) == 0) { 00112 if ((*index) == -1) { 00113 *index = 0; 00114 } 00115 else { 00116 PyErr_Format(PyExc_TypeError, 00117 "%.200s index %d was given while property \"%s\" is not an array", 00118 error_prefix, *index, path); 00119 return -1; 00120 } 00121 } 00122 else { 00123 int array_len = RNA_property_array_length(&r_ptr, prop); 00124 if ((*index) < -1 || (*index) >= array_len) { 00125 PyErr_Format(PyExc_TypeError, 00126 "%.200s index out of range \"%s\", given %d, array length is %d", 00127 error_prefix, path, *index, array_len); 00128 return -1; 00129 } 00130 } 00131 00132 if (is_idbase) { 00133 *path_full = BLI_strdup(path); 00134 } 00135 else { 00136 *path_full = RNA_path_from_ID_to_property(&r_ptr, prop); 00137 00138 if (*path_full == NULL) { 00139 PyErr_Format(PyExc_TypeError, 00140 "%.200s could not make path to \"%s\"", 00141 error_prefix, path); 00142 return -1; 00143 } 00144 } 00145 00146 return 0; 00147 } 00148 00149 /* internal use for insert and delete */ 00150 static int pyrna_struct_keyframe_parse( 00151 PointerRNA *ptr, PyObject *args, PyObject *kw, const char *parse_str, const char *error_prefix, 00152 const char **path_full, int *index, float *cfra, const char **group_name) /* return values */ 00153 { 00154 static const char *kwlist[] = {"data_path", "index", "frame", "group", NULL}; 00155 const char *path; 00156 00157 /* note, parse_str MUST start with 's|ifs' */ 00158 if (!PyArg_ParseTupleAndKeywords(args, kw, parse_str, (char **)kwlist, &path, index, cfra, group_name)) 00159 return -1; 00160 00161 if (pyrna_struct_anim_args_parse(ptr, error_prefix, path, path_full, index) < 0) 00162 return -1; 00163 00164 if (*cfra == FLT_MAX) 00165 *cfra = CTX_data_scene(BPy_GetContext())->r.cfra; 00166 00167 return 0; /* success */ 00168 } 00169 00170 char pyrna_struct_keyframe_insert_doc[] = 00171 ".. method:: keyframe_insert(data_path, index=-1, frame=bpy.context.scene.frame_current, group=\"\")\n" 00172 "\n" 00173 " Insert a keyframe on the property given, adding fcurves and animation data when necessary.\n" 00174 "\n" 00175 " :arg data_path: path to the property to key, analogous to the fcurve's data path.\n" 00176 " :type data_path: string\n" 00177 " :arg index: array index of the property to key. Defaults to -1 which will key all indices or a single channel if the property is not an array.\n" 00178 " :type index: int\n" 00179 " :arg frame: The frame on which the keyframe is inserted, defaulting to the current frame.\n" 00180 " :type frame: float\n" 00181 " :arg group: The name of the group the F-Curve should be added to if it doesn't exist yet.\n" 00182 " :type group: str\n" 00183 " :return: Success of keyframe insertion.\n" 00184 " :rtype: boolean\n" 00185 ; 00186 PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyObject *kw) 00187 { 00188 /* args, pyrna_struct_keyframe_parse handles these */ 00189 const char *path_full = NULL; 00190 int index = -1; 00191 float cfra = FLT_MAX; 00192 const char *group_name = NULL; 00193 00194 PYRNA_STRUCT_CHECK_OBJ(self); 00195 00196 if (pyrna_struct_keyframe_parse(&self->ptr, args, kw, 00197 "s|ifs:bpy_struct.keyframe_insert()", "bpy_struct.keyframe_insert()", 00198 &path_full, &index, &cfra, &group_name) == -1) 00199 { 00200 return NULL; 00201 } 00202 else { 00203 short result; 00204 ReportList reports; 00205 00206 BKE_reports_init(&reports, RPT_STORE); 00207 00208 result = insert_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0); 00209 MEM_freeN((void *)path_full); 00210 00211 if (BPy_reports_to_error(&reports, PyExc_RuntimeError, TRUE) == -1) 00212 return NULL; 00213 00214 return PyBool_FromLong(result); 00215 } 00216 } 00217 00218 char pyrna_struct_keyframe_delete_doc[] = 00219 ".. method:: keyframe_delete(data_path, index=-1, frame=bpy.context.scene.frame_current, group=\"\")\n" 00220 "\n" 00221 " Remove a keyframe from this properties fcurve.\n" 00222 "\n" 00223 " :arg data_path: path to the property to remove a key, analogous to the fcurve's data path.\n" 00224 " :type data_path: string\n" 00225 " :arg index: array index of the property to remove a key. Defaults to -1 removing all indices or a single channel if the property is not an array.\n" 00226 " :type index: int\n" 00227 " :arg frame: The frame on which the keyframe is deleted, defaulting to the current frame.\n" 00228 " :type frame: float\n" 00229 " :arg group: The name of the group the F-Curve should be added to if it doesn't exist yet.\n" 00230 " :type group: str\n" 00231 " :return: Success of keyframe deleation.\n" 00232 " :rtype: boolean\n" 00233 ; 00234 PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyObject *kw) 00235 { 00236 /* args, pyrna_struct_keyframe_parse handles these */ 00237 const char *path_full = NULL; 00238 int index = -1; 00239 float cfra = FLT_MAX; 00240 const char *group_name = NULL; 00241 00242 PYRNA_STRUCT_CHECK_OBJ(self); 00243 00244 if (pyrna_struct_keyframe_parse(&self->ptr, args, kw, 00245 "s|ifs:bpy_struct.keyframe_delete()", 00246 "bpy_struct.keyframe_insert()", 00247 &path_full, &index, &cfra, &group_name) == -1) 00248 { 00249 return NULL; 00250 } 00251 else { 00252 short result; 00253 ReportList reports; 00254 00255 BKE_reports_init(&reports, RPT_STORE); 00256 00257 result = delete_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0); 00258 MEM_freeN((void *)path_full); 00259 00260 if (BPy_reports_to_error(&reports, PyExc_RuntimeError, TRUE) == -1) 00261 return NULL; 00262 00263 return PyBool_FromLong(result); 00264 } 00265 00266 } 00267 00268 char pyrna_struct_driver_add_doc[] = 00269 ".. method:: driver_add(path, index=-1)\n" 00270 "\n" 00271 " Adds driver(s) to the given property\n" 00272 "\n" 00273 " :arg path: path to the property to drive, analogous to the fcurve's data path.\n" 00274 " :type path: string\n" 00275 " :arg index: array index of the property drive. Defaults to -1 for all indices or a single channel if the property is not an array.\n" 00276 " :type index: int\n" 00277 " :return: The driver(s) added.\n" 00278 " :rtype: :class:`bpy.types.FCurve` or list if index is -1 with an array property.\n" 00279 ; 00280 PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args) 00281 { 00282 const char *path, *path_full; 00283 int index = -1; 00284 00285 PYRNA_STRUCT_CHECK_OBJ(self); 00286 00287 if (!PyArg_ParseTuple(args, "s|i:driver_add", &path, &index)) 00288 return NULL; 00289 00290 if (pyrna_struct_anim_args_parse(&self->ptr, "bpy_struct.driver_add():", path, &path_full, &index) < 0) { 00291 return NULL; 00292 } 00293 else { 00294 PyObject *ret = NULL; 00295 ReportList reports; 00296 int result; 00297 00298 BKE_reports_init(&reports, RPT_STORE); 00299 00300 result = ANIM_add_driver(&reports, (ID *)self->ptr.id.data, path_full, index, 0, DRIVER_TYPE_PYTHON); 00301 00302 if (BPy_reports_to_error(&reports, PyExc_RuntimeError, TRUE) == -1) 00303 return NULL; 00304 00305 if (result) { 00306 ID *id = self->ptr.id.data; 00307 AnimData *adt = BKE_animdata_from_id(id); 00308 FCurve *fcu; 00309 00310 PointerRNA tptr; 00311 PyObject *item; 00312 00313 if (index == -1) { /* all, use a list */ 00314 int i = 0; 00315 ret = PyList_New(0); 00316 while ((fcu = list_find_fcurve(&adt->drivers, path_full, i++))) { 00317 RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr); 00318 item = pyrna_struct_CreatePyObject(&tptr); 00319 PyList_Append(ret, item); 00320 Py_DECREF(item); 00321 } 00322 } 00323 else { 00324 fcu = list_find_fcurve(&adt->drivers, path_full, index); 00325 RNA_pointer_create(id, &RNA_FCurve, fcu, &tptr); 00326 ret = pyrna_struct_CreatePyObject(&tptr); 00327 } 00328 00329 WM_event_add_notifier(BPy_GetContext(), NC_ANIMATION|ND_FCURVES_ORDER, NULL); 00330 } 00331 else { 00332 /* XXX, should be handled by reports, */ 00333 PyErr_SetString(PyExc_TypeError, "bpy_struct.driver_add(): failed because of an internal error"); 00334 return NULL; 00335 } 00336 00337 MEM_freeN((void *)path_full); 00338 00339 return ret; 00340 } 00341 } 00342 00343 00344 char pyrna_struct_driver_remove_doc[] = 00345 ".. method:: driver_remove(path, index=-1)\n" 00346 "\n" 00347 " Remove driver(s) from the given property\n" 00348 "\n" 00349 " :arg path: path to the property to drive, analogous to the fcurve's data path.\n" 00350 " :type path: string\n" 00351 " :arg index: array index of the property drive. Defaults to -1 for all indices or a single channel if the property is not an array.\n" 00352 " :type index: int\n" 00353 " :return: Success of driver removal.\n" 00354 " :rtype: boolean\n" 00355 ; 00356 PyObject *pyrna_struct_driver_remove(BPy_StructRNA *self, PyObject *args) 00357 { 00358 const char *path, *path_full; 00359 int index = -1; 00360 00361 PYRNA_STRUCT_CHECK_OBJ(self); 00362 00363 if (!PyArg_ParseTuple(args, "s|i:driver_remove", &path, &index)) 00364 return NULL; 00365 00366 if (pyrna_struct_anim_args_parse(&self->ptr, "bpy_struct.driver_remove():", path, &path_full, &index) < 0) { 00367 return NULL; 00368 } 00369 else { 00370 short result; 00371 ReportList reports; 00372 00373 BKE_reports_init(&reports, RPT_STORE); 00374 00375 result = ANIM_remove_driver(&reports, (ID *)self->ptr.id.data, path_full, index, 0); 00376 00377 MEM_freeN((void *)path_full); 00378 00379 if (BPy_reports_to_error(&reports, PyExc_RuntimeError, TRUE) == -1) 00380 return NULL; 00381 00382 WM_event_add_notifier(BPy_GetContext(), NC_ANIMATION|ND_FCURVES_ORDER, NULL); 00383 00384 return PyBool_FromLong(result); 00385 } 00386 }