/** * called from both exec & poll * * \note: normally we wouldn't call a loop from within a poll function, * However this is a special case, and for regular poll calls, getting * the context from the button will fail early. */ static bool copy_to_selected_button(bContext *C, bool all, bool poll) { PointerRNA ptr, lptr, idptr; PropertyRNA *prop, *lprop; bool success = false; int index; /* try to reset the nominated setting to its default value */ uiContextActiveProperty(C, &ptr, &prop, &index); /* if there is a valid property that is editable... */ if (ptr.data && prop) { char *path = NULL; bool use_path; CollectionPointerLink *link; ListBase lb; if (!copy_to_selected_list(C, &ptr, &lb, &use_path)) return success; if (!use_path || (path = RNA_path_from_ID_to_property(&ptr, prop))) { for (link = lb.first; link; link = link->next) { if (link->ptr.data != ptr.data) { if (use_path) { lprop = NULL; RNA_id_pointer_create(link->ptr.id.data, &idptr); RNA_path_resolve_property(&idptr, path, &lptr, &lprop); } else { lptr = link->ptr; lprop = prop; } if (lprop == prop) { if (RNA_property_editable(&lptr, lprop)) { if (poll) { success = true; break; } else { if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) { RNA_property_update(C, &lptr, prop); success = true; } } } } } } if (path) MEM_freeN(path); } BLI_freelistN(&lb); } return success; }
/* create new expression for button (i.e. a "scripted driver"), if it can be created... */ bool ui_but_anim_expression_create(uiBut *but, const char *str) { bContext *C = but->block->evil_C; ID *id; FCurve *fcu; char *path; bool ok = false; /* button must have RNA-pointer to a numeric-capable property */ if (ELEM(NULL, but->rnapoin.data, but->rnaprop)) { if (G.debug & G_DEBUG) printf("ERROR: create expression failed - button has no RNA info attached\n"); return false; } if (RNA_property_array_check(but->rnaprop) != 0) { if (but->rnaindex == -1) { if (G.debug & G_DEBUG) printf("ERROR: create expression failed - can't create expression for entire array\n"); return false; } } /* make sure we have animdata for this */ /* FIXME: until materials can be handled by depsgraph, don't allow drivers to be created for them */ id = (ID *)but->rnapoin.id.data; if ((id == NULL) || (GS(id->name) == ID_MA) || (GS(id->name) == ID_TE)) { if (G.debug & G_DEBUG) printf("ERROR: create expression failed - invalid id-datablock for adding drivers (%p)\n", id); return false; } /* get path */ path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop); /* create driver */ fcu = verify_driver_fcurve(id, path, but->rnaindex, 1); if (fcu) { ChannelDriver *driver = fcu->driver; if (driver) { /* set type of driver */ driver->type = DRIVER_TYPE_PYTHON; /* set the expression */ /* TODO: need some way of identifying variables used */ BLI_strncpy_utf8(driver->expression, str, sizeof(driver->expression)); /* updates */ driver->flag |= DRIVER_FLAG_RECOMPILE; WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME, NULL); ok = true; } } MEM_freeN(path); return ok; }
static int remove_keyingset_button_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); KeyingSet *ks = NULL; PropertyRNA *prop = NULL; PointerRNA ptr = {{NULL}}; char *path = NULL; short success = 0; int index = 0; /* verify the Keying Set to use: * - use the active one for now (more control over this can be added later) * - return error if it doesn't exist */ if (scene->active_keyingset == 0) { BKE_report(op->reports, RPT_ERROR, "No active keying set to remove property from"); return OPERATOR_CANCELLED; } else if (scene->active_keyingset < 0) { BKE_report(op->reports, RPT_ERROR, "Cannot remove property from built in keying set"); return OPERATOR_CANCELLED; } else { ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); } /* try to add to keyingset using property retrieved from UI */ uiContextActiveProperty(C, &ptr, &prop, &index); if (ptr.id.data && ptr.data && prop) { path = RNA_path_from_ID_to_property(&ptr, prop); if (path) { KS_Path *ksp; /* try to find a path matching this description */ ksp = BKE_keyingset_find_path(ks, ptr.id.data, ks->name, path, index, KSP_GROUP_KSNAME); if (ksp) { BKE_keyingset_free_path(ks, ksp); success = 1; } /* free temp path used */ MEM_freeN(path); } } if (success) { /* send updates */ WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); /* show warning */ BKE_report(op->reports, RPT_INFO, "Property removed from Keying Set"); } return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; }
static int remove_keyingset_button_exec (bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); KeyingSet *ks = NULL; PropertyRNA *prop= NULL; PointerRNA ptr; char *path = NULL; short success= 0; int index=0; /* verify the Keying Set to use: * - use the active one for now (more control over this can be added later) * - return error if it doesn't exist */ if (scene->active_keyingset == 0) { BKE_report(op->reports, RPT_ERROR, "No active Keying Set to remove property from"); return OPERATOR_CANCELLED; } else ks= BLI_findlink(&scene->keyingsets, scene->active_keyingset-1); /* try to add to keyingset using property retrieved from UI */ memset(&ptr, 0, sizeof(PointerRNA)); uiAnimContextProperty(C, &ptr, &prop, &index); if (ptr.data && prop) { path= RNA_path_from_ID_to_property(&ptr, prop); if (path) { KS_Path *ksp; /* try to find a path matching this description */ ksp= BKE_keyingset_find_destination(ks, ptr.id.data, ks->name, path, index, KSP_GROUP_KSNAME); if (ksp) { /* just free it... */ MEM_freeN(ksp->rna_path); BLI_freelinkN(&ks->paths, ksp); success= 1; } /* free temp path used */ MEM_freeN(path); } } if (success) { /* send updates */ ED_anim_dag_flush_update(C); /* for now, only send ND_KEYS for KeyingSets */ WM_event_add_notifier(C, NC_SCENE|ND_KEYINGSET, NULL); } return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED; }
/* Temporary wrapper for driver operators for buttons to make it easier to create * such drivers by rerouting all paths through the active object instead so that * they will get picked up by the dependency system. * * < C: context pointer - for getting active data * <> ptr: RNA pointer for property's datablock. May be modified as result of path remapping. * < prop: RNA definition of property to add for * * > returns: MEM_alloc'd string representing the path to the property from the given PointerRNA */ static char *get_driver_path_hack(bContext *C, PointerRNA *ptr, PropertyRNA *prop) { ID *id = (ID *)ptr->id.data; ScrArea *sa = CTX_wm_area(C); /* get standard path which may be extended */ char *basepath = RNA_path_from_ID_to_property(ptr, prop); char *path = basepath; /* in case no remapping is needed */ /* Remapping will only be performed in the Properties Editor, as only this * restricts the subspace of options to the 'active' data (a manageable state) */ // TODO: watch out for pinned context? if ((sa) && (sa->spacetype == SPACE_BUTS)) { Object *ob = CTX_data_active_object(C); if (ob && id) { /* only id-types which can be remapped to go through objects should be considered */ switch (GS(id->name)) { case ID_TE: /* textures */ { Material *ma = give_current_material(ob, ob->actcol); Tex *tex = give_current_material_texture(ma); /* assumes: texture will only be shown if it is active material's active texture it's ok */ if ((ID *)tex == id) { char name_esc_ma[(sizeof(ma->id.name) - 2) * 2]; char name_esc_tex[(sizeof(tex->id.name) - 2) * 2]; BLI_strescape(name_esc_ma, ma->id.name + 2, sizeof(name_esc_ma)); BLI_strescape(name_esc_tex, tex->id.name + 2, sizeof(name_esc_tex)); /* create new path */ // TODO: use RNA path functions to construct step by step instead? // FIXME: maybe this isn't even needed anymore... path = BLI_sprintfN("material_slots[\"%s\"].material.texture_slots[\"%s\"].texture.%s", name_esc_ma, name_esc_tex, basepath); /* free old one */ MEM_freeN(basepath); } break; } } /* fix RNA pointer, as we've now changed the ID root by changing the paths */ if (basepath != path) { /* rebase provided pointer so that it starts from object... */ RNA_pointer_create(&ob->id, ptr->type, ptr->data, ptr); } } } /* the path should now have been corrected for use */ return path; }
static int copy_to_selected_button_exec(bContext *C, wmOperator *op) { PointerRNA ptr, lptr, idptr; PropertyRNA *prop, *lprop; int success = 0; int index, all = RNA_boolean_get(op->ptr, "all"); /* try to reset the nominated setting to its default value */ uiContextActiveProperty(C, &ptr, &prop, &index); /* if there is a valid property that is editable... */ if (ptr.data && prop) { char *path = NULL; int use_path; CollectionPointerLink *link; ListBase lb; if (!copy_to_selected_list(C, &ptr, &lb, &use_path)) return success; if (!use_path || (path = RNA_path_from_ID_to_property(&ptr, prop))) { for (link = lb.first; link; link = link->next) { if (link->ptr.data != ptr.data) { if (use_path) { lprop = NULL; RNA_id_pointer_create(link->ptr.id.data, &idptr); RNA_path_resolve(&idptr, path, &lptr, &lprop); } else { lptr = link->ptr; lprop = prop; } if (lprop == prop) { if (RNA_property_editable(&lptr, lprop)) { if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) { RNA_property_update(C, &lptr, prop); success = 1; } } } } } if (path) MEM_freeN(path); } BLI_freelistN(&lb); } return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; }
static int copy_to_selected_button_poll(bContext *C) { PointerRNA ptr, lptr, idptr; PropertyRNA *prop, *lprop; int index, success = 0; uiContextActiveProperty(C, &ptr, &prop, &index); if (ptr.data && prop) { char *path = NULL; int use_path; CollectionPointerLink *link; ListBase lb; if (!copy_to_selected_list(C, &ptr, &lb, &use_path)) return success; if (!use_path || (path = RNA_path_from_ID_to_property(&ptr, prop))) { for (link = lb.first; link; link = link->next) { if (link->ptr.data != ptr.data) { if (use_path) { lprop = NULL; RNA_id_pointer_create(link->ptr.id.data, &idptr); RNA_path_resolve(&idptr, path, &lptr, &lprop); } else { lptr = link->ptr; lprop = prop; } if (lprop == prop) { if (RNA_property_editable(&lptr, prop)) success = 1; } } } if (path) MEM_freeN(path); } BLI_freelistN(&lb); } return success; }
static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *event) { DriverDropper *ddr = (DriverDropper *)op->customdata; uiBut *but = eyedropper_get_property_button_under_mouse(C, event); short mapping_type = RNA_enum_get(op->ptr, "mapping_type"); short flag = 0; /* we can only add a driver if we know what RNA property it corresponds to */ if (but == NULL) { return; } else { /* Get paths for src... */ PointerRNA *target_ptr = &but->rnapoin; PropertyRNA *target_prop = but->rnaprop; int target_index = but->rnaindex; char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop); /* ... and destination */ char *dst_path = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL); /* Now create driver(s) */ if (target_path && dst_path) { int success = ANIM_add_driver_with_target(op->reports, ddr->ptr.id.data, dst_path, ddr->index, target_ptr->id.data, target_path, target_index, flag, DRIVER_TYPE_PYTHON, mapping_type); if (success) { /* send updates */ UI_context_update_anim_flag(C); DAG_relations_tag_update(CTX_data_main(C)); DAG_id_tag_update(ddr->ptr.id.data, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX } } /* cleanup */ if (target_path) MEM_freeN(target_path); if (dst_path) MEM_freeN(dst_path); } }
static FCurve *ui_but_get_fcurve(uiBut *but, bAction **action, int *driven) { FCurve *fcu= NULL; *driven= 0; /* there must be some RNA-pointer + property combo for this button */ if(but->rnaprop && but->rnapoin.id.data && RNA_property_animateable(&but->rnapoin, but->rnaprop)) { AnimData *adt= BKE_animdata_from_id(but->rnapoin.id.data); char *path; if(adt) { if((adt->action && adt->action->curves.first) || (adt->drivers.first)) { /* XXX this function call can become a performance bottleneck */ path= RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop); if(path) { /* animation takes priority over drivers */ if(adt->action && adt->action->curves.first) fcu= list_find_fcurve(&adt->action->curves, path, but->rnaindex); /* if not animated, check if driven */ if(!fcu && (adt->drivers.first)) { fcu= list_find_fcurve(&adt->drivers, path, but->rnaindex); if(fcu) *driven= 1; } if(fcu && action) *action= adt->action; MEM_freeN(path); } } } } return fcu; }
static int copy_data_path_button_poll(bContext *C) { PointerRNA ptr; PropertyRNA *prop; char *path; int index; uiContextActiveProperty(C, &ptr, &prop, &index); if (ptr.id.data && ptr.data && prop) { path = RNA_path_from_ID_to_property(&ptr, prop); if (path) { MEM_freeN(path); return 1; } } return 0; }
static bool copy_to_selected_list( bContext *C, PointerRNA *ptr, PropertyRNA *prop, ListBase *r_lb, bool *r_use_path_from_id, char **r_path) { *r_use_path_from_id = false; *r_path = NULL; if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) { *r_lb = CTX_data_collection_get(C, "selected_editable_bones"); } else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) { *r_lb = CTX_data_collection_get(C, "selected_pose_bones"); } else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) { *r_lb = CTX_data_collection_get(C, "selected_editable_sequences"); } else if (ptr->id.data) { ID *id = ptr->id.data; if (GS(id->name) == ID_OB) { *r_lb = CTX_data_collection_get(C, "selected_editable_objects"); *r_use_path_from_id = true; *r_path = RNA_path_from_ID_to_property(ptr, prop); } else if (GS(id->name) == ID_SCE) { /* Sequencer's ID is scene :/ */ /* Try to recursively find an RNA_Sequence ancestor, to handle situations like T41062... */ if ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) != NULL) { *r_lb = CTX_data_collection_get(C, "selected_editable_sequences"); } } return (*r_path != NULL); } else { return false; } return true; }
static int copy_data_path_button_exec(bContext *C, wmOperator *UNUSED(op)) { PointerRNA ptr; PropertyRNA *prop; char *path; int index; /* try to create driver using property retrieved from UI */ uiContextActiveProperty(C, &ptr, &prop, &index); if (ptr.id.data && ptr.data && prop) { path = RNA_path_from_ID_to_property(&ptr, prop); if (path) { WM_clipboard_text_set(path, false); MEM_freeN(path); return OPERATOR_FINISHED; } } return OPERATOR_CANCELLED; }
static int copy_data_path_button_exec(bContext *C, wmOperator *UNUSED(op)) { PointerRNA ptr; PropertyRNA *prop; char *path; int success= 0; int index; /* try to create driver using property retrieved from UI */ uiContextActiveProperty(C, &ptr, &prop, &index); if (ptr.id.data && ptr.data && prop) { path= RNA_path_from_ID_to_property(&ptr, prop); if (path) { WM_clipboard_text_set(path, FALSE); MEM_freeN(path); } } /* since we're just copying, we don't really need to do anything else...*/ return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED; }
static int copy_data_path_button_exec(bContext *C, wmOperator *op) { PointerRNA ptr; PropertyRNA *prop; char *path; int index; const bool full_path = RNA_boolean_get(op->ptr, "full_path"); /* try to create driver using property retrieved from UI */ UI_context_active_but_prop_get(C, &ptr, &prop, &index); if (ptr.id.data != NULL) { if (full_path) { if (prop) { path = RNA_path_full_property_py_ex(&ptr, prop, index, true); } else { path = RNA_path_full_struct_py(&ptr); } } else { path = RNA_path_from_ID_to_property(&ptr, prop); } if (path) { WM_clipboard_text_set(path, false); MEM_freeN(path); return OPERATOR_FINISHED; } } return OPERATOR_CANCELLED; }
static int add_keyingset_button_exec (bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); KeyingSet *ks = NULL; PropertyRNA *prop= NULL; PointerRNA ptr; char *path = NULL; short success= 0; int index=0, pflag=0; int all= RNA_boolean_get(op->ptr, "all"); /* verify the Keying Set to use: * - use the active one for now (more control over this can be added later) * - add a new one if it doesn't exist */ if (scene->active_keyingset == 0) { short flag=0, keyingflag=0; /* validate flags * - absolute KeyingSets should be created by default */ flag |= KEYINGSET_ABSOLUTE; if (IS_AUTOKEY_FLAG(AUTOMATKEY)) keyingflag |= INSERTKEY_MATRIX; if (IS_AUTOKEY_FLAG(INSERTNEEDED)) keyingflag |= INSERTKEY_NEEDED; /* call the API func, and set the active keyingset index */ ks= BKE_keyingset_add(&scene->keyingsets, "ButtonKeyingSet", flag, keyingflag); scene->active_keyingset= BLI_countlist(&scene->keyingsets); } else ks= BLI_findlink(&scene->keyingsets, scene->active_keyingset-1); /* try to add to keyingset using property retrieved from UI */ memset(&ptr, 0, sizeof(PointerRNA)); uiAnimContextProperty(C, &ptr, &prop, &index); /* check if property is able to be added */ if (ptr.data && prop && RNA_property_animateable(ptr.data, prop)) { path= RNA_path_from_ID_to_property(&ptr, prop); if (path) { /* set flags */ if (all) { pflag |= KSP_FLAG_WHOLE_ARRAY; /* we need to set the index for this to 0, even though it may break in some cases, this is * necessary if we want the entire array for most cases to get included without the user * having to worry about where they clicked */ index= 0; } /* add path to this setting */ BKE_keyingset_add_destination(ks, ptr.id.data, NULL, path, index, pflag, KSP_GROUP_KSNAME); ks->active_path= BLI_countlist(&ks->paths); success= 1; /* free the temp path created */ MEM_freeN(path); } } if (success) { /* send updates */ ED_anim_dag_flush_update(C); /* for now, only send ND_KEYS for KeyingSets */ WM_event_add_notifier(C, NC_SCENE|ND_KEYINGSET, NULL); } return (success)? OPERATOR_FINISHED: OPERATOR_CANCELLED; }
/* create new expression for button (i.e. a "scripted driver"), if it can be created... */ int ui_but_anim_expression_create(uiBut *but, const char *str) { bContext *C = but->block->evil_C; ID *id; FCurve *fcu; char *path; short ok=0; /* button must have RNA-pointer to a numeric-capable property */ if (ELEM(NULL, but->rnapoin.data, but->rnaprop)) { if (G.f & G_DEBUG) printf("ERROR: create expression failed - button has no RNA info attached\n"); return 0; } /* make sure we have animdata for this */ // FIXME: until materials can be handled by depsgraph, don't allow drivers to be created for them id = (ID *)but->rnapoin.id.data; if ((id == NULL) || (GS(id->name)==ID_MA) || (GS(id->name)==ID_TE)) { if (G.f & G_DEBUG) printf("ERROR: create expression failed - invalid id-datablock for adding drivers (%p)\n", id); return 0; } /* get path */ path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop); /* create driver */ fcu = verify_driver_fcurve(id, path, but->rnaindex, 1); if (fcu) { ChannelDriver *driver= fcu->driver; if (driver) { /* set type of driver */ driver->type = DRIVER_TYPE_PYTHON; /* set the expression */ // TODO: need some way of identifying variables used BLI_strncpy(driver->expression, str, sizeof(driver->expression)); /* FIXME: for now, assume that * - for expressions, users are likely to be using "frame" -> current frame" as a variable * - driver_add_new_variable() adds a single-prop variable by default */ { DriverVar *dvar; DriverTarget *dtar; dvar = driver_add_new_variable(driver); BLI_strncpy(dvar->name, "frame", sizeof(dvar->name)); dtar = &dvar->targets[0]; dtar->id = (ID *)CTX_data_scene(C); // XXX: should we check that C is valid first? dtar->rna_path = BLI_sprintfN("frame_current"); } /* updates */ driver->flag |= DRIVER_FLAG_RECOMPILE; WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME, NULL); } } MEM_freeN(path); return ok; }
static int add_keyingset_button_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); KeyingSet *ks = NULL; PropertyRNA *prop = NULL; PointerRNA ptr = {{NULL}}; char *path = NULL; short success = 0; int index = 0, pflag = 0; const bool all = RNA_boolean_get(op->ptr, "all"); /* verify the Keying Set to use: * - use the active one for now (more control over this can be added later) * - add a new one if it doesn't exist */ if (scene->active_keyingset == 0) { short flag = 0, keyingflag = 0; /* validate flags * - absolute KeyingSets should be created by default */ flag |= KEYINGSET_ABSOLUTE; keyingflag |= ANIM_get_keyframing_flags(scene, 0); if (IS_AUTOKEY_FLAG(scene, XYZ2RGB)) keyingflag |= INSERTKEY_XYZ2RGB; /* call the API func, and set the active keyingset index */ ks = BKE_keyingset_add(&scene->keyingsets, "ButtonKeyingSet", "Button Keying Set", flag, keyingflag); scene->active_keyingset = BLI_countlist(&scene->keyingsets); } else if (scene->active_keyingset < 0) { BKE_report(op->reports, RPT_ERROR, "Cannot add property to built in keying set"); return OPERATOR_CANCELLED; } else { ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); } /* try to add to keyingset using property retrieved from UI */ uiContextActiveProperty(C, &ptr, &prop, &index); /* check if property is able to be added */ if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { path = RNA_path_from_ID_to_property(&ptr, prop); if (path) { /* set flags */ if (all) { pflag |= KSP_FLAG_WHOLE_ARRAY; /* we need to set the index for this to 0, even though it may break in some cases, this is * necessary if we want the entire array for most cases to get included without the user * having to worry about where they clicked */ index = 0; } /* add path to this setting */ BKE_keyingset_add_path(ks, ptr.id.data, NULL, path, index, pflag, KSP_GROUP_KSNAME); ks->active_path = BLI_countlist(&ks->paths); success = 1; /* free the temp path created */ MEM_freeN(path); } } if (success) { /* send updates */ WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); /* show notification/report header, so that users notice that something changed */ BKE_reportf(op->reports, RPT_INFO, "Property added to Keying Set: '%s'", ks->name); } return (success) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; }
bool UI_context_copy_to_selected_list(bContext *C, PointerRNA *ptr, PropertyRNA *prop, ListBase *r_lb, bool *r_use_path_from_id, char **r_path) { *r_use_path_from_id = false; *r_path = NULL; if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) { *r_lb = CTX_data_collection_get(C, "selected_editable_bones"); } else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) { *r_lb = CTX_data_collection_get(C, "selected_pose_bones"); } else if (RNA_struct_is_a(ptr->type, &RNA_Bone)) { ListBase lb; lb = CTX_data_collection_get(C, "selected_pose_bones"); if (!BLI_listbase_is_empty(&lb)) { CollectionPointerLink *link; for (link = lb.first; link; link = link->next) { bPoseChannel *pchan = link->ptr.data; RNA_pointer_create(link->ptr.id.data, &RNA_Bone, pchan->bone, &link->ptr); } } *r_lb = lb; } else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) { *r_lb = CTX_data_collection_get(C, "selected_editable_sequences"); } else if (RNA_struct_is_a(ptr->type, &RNA_FCurve)) { *r_lb = CTX_data_collection_get(C, "selected_editable_fcurves"); } else if (RNA_struct_is_a(ptr->type, &RNA_Node) || RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) { ListBase lb = {NULL, NULL}; char *path = NULL; bNode *node = NULL; /* Get the node we're editing */ if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) { bNodeTree *ntree = ptr->id.data; bNodeSocket *sock = ptr->data; if (nodeFindNode(ntree, sock, &node, NULL)) { if ((path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Node)) != NULL) { /* we're good! */ } else { node = NULL; } } } else { node = ptr->data; } /* Now filter by type */ if (node) { CollectionPointerLink *link, *link_next; lb = CTX_data_collection_get(C, "selected_nodes"); for (link = lb.first; link; link = link_next) { bNode *node_data = link->ptr.data; link_next = link->next; if (node_data->type != node->type) { BLI_remlink(&lb, link); MEM_freeN(link); } } } *r_lb = lb; *r_path = path; } else if (ptr->id.data) { ID *id = ptr->id.data; if (GS(id->name) == ID_OB) { *r_lb = CTX_data_collection_get(C, "selected_editable_objects"); *r_use_path_from_id = true; *r_path = RNA_path_from_ID_to_property(ptr, prop); } else if (OB_DATA_SUPPORT_ID(GS(id->name))) { /* check we're using the active object */ const short id_code = GS(id->name); ListBase lb = CTX_data_collection_get(C, "selected_editable_objects"); char *path = RNA_path_from_ID_to_property(ptr, prop); /* de-duplicate obdata */ if (!BLI_listbase_is_empty(&lb)) { CollectionPointerLink *link, *link_next; for (link = lb.first; link; link = link->next) { Object *ob = link->ptr.id.data; if (ob->data) { ID *id_data = ob->data; id_data->tag |= LIB_TAG_DOIT; } } for (link = lb.first; link; link = link_next) { Object *ob = link->ptr.id.data; ID *id_data = ob->data; link_next = link->next; if ((id_data == NULL) || (id_data->tag & LIB_TAG_DOIT) == 0 || ID_IS_LINKED(id_data) || (GS(id_data->name) != id_code)) { BLI_remlink(&lb, link); MEM_freeN(link); } else { /* avoid prepending 'data' to the path */ RNA_id_pointer_create(id_data, &link->ptr); } if (id_data) { id_data->tag &= ~LIB_TAG_DOIT; } } } *r_lb = lb; *r_path = path; } else if (GS(id->name) == ID_SCE) { /* Sequencer's ID is scene :/ */ /* Try to recursively find an RNA_Sequence ancestor, * to handle situations like T41062... */ if ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) != NULL) { *r_lb = CTX_data_collection_get(C, "selected_editable_sequences"); } } return (*r_path != NULL); } else { return false; } return true; }
/* for keyframes and drivers */ static int pyrna_struct_anim_args_parse( PointerRNA *ptr, const char *error_prefix, const char *path, const char **path_full, int *index) { const bool is_idbase = RNA_struct_is_ID(ptr->type); PropertyRNA *prop; PointerRNA r_ptr; if (ptr->data == NULL) { PyErr_Format(PyExc_TypeError, "%.200s this struct has no data, can't be animated", error_prefix); return -1; } /* full paths can only be given from ID base */ if (is_idbase) { int r_index = -1; if (RNA_path_resolve_property_full(ptr, path, &r_ptr, &prop, &r_index) == false) { prop = NULL; } else if (r_index != -1) { PyErr_Format(PyExc_ValueError, "%.200s path includes index, must be a separate argument", error_prefix, path); return -1; } else if (ptr->id.data != r_ptr.id.data) { PyErr_Format(PyExc_ValueError, "%.200s path spans ID blocks", error_prefix, path); return -1; } } else { prop = RNA_struct_find_property(ptr, path); r_ptr = *ptr; } if (prop == NULL) { PyErr_Format(PyExc_TypeError, "%.200s property \"%s\" not found", error_prefix, path); return -1; } if (!RNA_property_animateable(&r_ptr, prop)) { PyErr_Format(PyExc_TypeError, "%.200s property \"%s\" not animatable", error_prefix, path); return -1; } if (RNA_property_array_check(prop) == 0) { if ((*index) == -1) { *index = 0; } else { PyErr_Format(PyExc_TypeError, "%.200s index %d was given while property \"%s\" is not an array", error_prefix, *index, path); return -1; } } else { int array_len = RNA_property_array_length(&r_ptr, prop); if ((*index) < -1 || (*index) >= array_len) { PyErr_Format(PyExc_TypeError, "%.200s index out of range \"%s\", given %d, array length is %d", error_prefix, path, *index, array_len); return -1; } } if (is_idbase) { *path_full = BLI_strdup(path); } else { *path_full = RNA_path_from_ID_to_property(&r_ptr, prop); if (*path_full == NULL) { PyErr_Format(PyExc_TypeError, "%.200s could not make path to \"%s\"", error_prefix, path); return -1; } } return 0; }