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