/* Get unit conversion factor for given ID + F-Curve */ float ANIM_unit_mapping_get_factor(Scene *scene, ID *id, FCurve *fcu, short restore) { /* sanity checks */ if (id && fcu && fcu->rna_path) { PointerRNA ptr, id_ptr; PropertyRNA *prop; /* get RNA property that F-Curve affects */ RNA_id_pointer_create(id, &id_ptr); if (RNA_path_resolve(&id_ptr, fcu->rna_path, &ptr, &prop)) { /* rotations: radians <-> degrees? */ if (RNA_SUBTYPE_UNIT(RNA_property_subtype(prop)) == PROP_UNIT_ROTATION) { /* if the radians flag is not set, default to using degrees which need conversions */ if ((scene) && (scene->unit.system_rotation == USER_UNIT_ROT_RADIANS) == 0) { if (restore) return DEG2RADF(1.0f); /* degrees to radians */ else return RAD2DEGF(1.0f); /* radians to degrees */ } } /* TODO: other rotation types here as necessary */ } } /* no mapping needs to occur... */ return 1.0f; }
int UI_pie_menu_invoke_from_rna_enum( struct bContext *C, const char *title, const char *path, const wmEvent *event) { PointerRNA ctx_ptr; PointerRNA r_ptr; PropertyRNA *r_prop; uiPieMenu *pie; uiLayout *layout; RNA_pointer_create(NULL, &RNA_Context, C, &ctx_ptr); if (!RNA_path_resolve(&ctx_ptr, path, &r_ptr, &r_prop)) { return OPERATOR_CANCELLED; } /* invalid property, only accept enums */ if (RNA_property_type(r_prop) != PROP_ENUM) { BLI_assert(0); return OPERATOR_CANCELLED; } pie = UI_pie_menu_begin(C, IFACE_(title), ICON_NONE, event); layout = UI_pie_menu_layout(pie); layout = uiLayoutRadial(layout); uiItemFullR(layout, &r_ptr, r_prop, RNA_NO_INDEX, 0, UI_ITEM_R_EXPAND, NULL, 0); UI_pie_menu_end(C, pie); return OPERATOR_INTERFACE; }
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; }
/* Main Driver Management API calls: * Add a new driver for the specified property on the given ID block or replace an existing one * with the driver + driver-curve data from the buffer */ short ANIM_paste_driver (ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag)) { PointerRNA id_ptr, ptr; PropertyRNA *prop; FCurve *fcu; /* validate pointer first - exit if failure */ RNA_id_pointer_create(id, &id_ptr); if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) { BKE_reportf(reports, RPT_ERROR, "Could not paste Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)", id->name, rna_path); return 0; } /* if the buffer is empty, cannot paste... */ if (channeldriver_copypaste_buf == NULL) { BKE_report(reports, RPT_ERROR, "Paste Driver: No Driver to paste"); return 0; } /* create Driver F-Curve, but without data which will be copied across... */ fcu= verify_driver_fcurve(id, rna_path, array_index, -1); if (fcu) { /* copy across the curve data from the buffer curve * NOTE: this step needs care to not miss new settings */ /* keyframes/samples */ fcu->bezt= MEM_dupallocN(channeldriver_copypaste_buf->bezt); fcu->fpt= MEM_dupallocN(channeldriver_copypaste_buf->fpt); fcu->totvert= channeldriver_copypaste_buf->totvert; /* modifiers */ copy_fmodifiers(&fcu->modifiers, &channeldriver_copypaste_buf->modifiers); /* extrapolation mode */ fcu->extend= channeldriver_copypaste_buf->extend; /* the 'juicy' stuff - the driver */ fcu->driver= fcurve_copy_driver(channeldriver_copypaste_buf->driver); } /* done */ return (fcu != NULL); }
/* medium match strictness: path match only (i.e. ignore ID) */ static tAnimCopybufItem *pastebuf_match_path_property(FCurve *fcu, const short from_single, const short UNUSED(to_simple)) { tAnimCopybufItem *aci; for (aci= animcopybuf.first; aci; aci= aci->next) { /* check that paths exist */ if (aci->rna_path && fcu->rna_path) { /* find the property of the fcurve and compare against the end of the tAnimCopybufItem * more involved since it needs to to path lookups. * This is not 100% reliable since the user could be editing the curves on a path that wont * resolve, or a bone could be renamed after copying for eg. but in normal copy & paste * this should work out ok. */ if (BLI_findindex(which_libbase(G.main, aci->id_type), aci->id) == -1) { /* pedantic but the ID could have been removed, and beats crashing! */ printf("paste_animedit_keys: error ID has been removed!\n"); } else { PointerRNA id_ptr, rptr; PropertyRNA *prop; RNA_id_pointer_create(aci->id, &id_ptr); RNA_path_resolve(&id_ptr, aci->rna_path, &rptr, &prop); if (prop) { const char *identifier= RNA_property_identifier(prop); int len_id = strlen(identifier); int len_path = strlen(fcu->rna_path); if (len_id <= len_path) { /* note, paths which end with "] will fail with this test - Animated ID Props */ if (strcmp(identifier, fcu->rna_path + (len_path-len_id))==0) { if ((from_single) || (aci->array_index == fcu->array_index)) break; } } } else { printf("paste_animedit_keys: failed to resolve path id:%s, '%s'!\n", aci->id->name, aci->rna_path); } } } } return aci; }
/* Main Driver Management API calls: * Make a copy of the driver for the specified property on the given ID block */ short ANIM_copy_driver (ReportList *reports, ID *id, const char rna_path[], int array_index, short UNUSED(flag)) { PointerRNA id_ptr, ptr; PropertyRNA *prop; FCurve *fcu; /* validate pointer first - exit if failure */ RNA_id_pointer_create(id, &id_ptr); if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) { BKE_reportf(reports, RPT_ERROR, "Could not find Driver to copy, as RNA Path is invalid for the given ID (ID = %s, Path = %s)", id->name, rna_path); return 0; } /* try to get F-Curve with Driver */ fcu= verify_driver_fcurve(id, rna_path, array_index, 0); /* clear copy/paste buffer first (for consistency with other copy/paste buffers) */ free_anim_drivers_copybuf(); /* copy this to the copy/paste buf if it exists */ if (fcu && fcu->driver) { /* make copies of some info such as the rna_path, then clear this info from the F-Curve temporarily * so that we don't end up wasting memory storing the path which won't get used ever... */ char *tmp_path = fcu->rna_path; fcu->rna_path= NULL; /* make a copy of the F-Curve with */ channeldriver_copypaste_buf= copy_fcurve(fcu); /* restore the path */ fcu->rna_path= tmp_path; /* copied... */ return 1; } /* done */ return 0; }
/* tags the given anim list element for refreshes (if applicable) * due to Animation Editor editing */ void ANIM_list_elem_update(Scene *scene, bAnimListElem *ale) { ID *id; FCurve *fcu; AnimData *adt; id= ale->id; if (!id) return; /* tag AnimData for refresh so that other views will update in realtime with these changes */ adt= BKE_animdata_from_id(id); if (adt) adt->recalc |= ADT_RECALC_ANIM; /* update data */ fcu= (ale->datatype == ALE_FCURVE)? ale->key_data: NULL; if (fcu && fcu->rna_path) { /* if we have an fcurve, call the update for the property we are editing, this is then expected to do the proper redraws and depsgraph updates */ PointerRNA id_ptr, ptr; PropertyRNA *prop; RNA_id_pointer_create(id, &id_ptr); if(RNA_path_resolve(&id_ptr, fcu->rna_path, &ptr, &prop)) RNA_property_update_main(G.main, scene, &ptr, prop); } else { /* in other case we do standard depsgaph update, ideally we'd be calling property update functions here too ... */ DAG_id_tag_update(id, OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME); // XXX or do we want something more restrictive? } }
static void graph_panel_key_properties(const bContext *C, Panel *pa) { bAnimListElem *ale; FCurve *fcu; BezTriple *bezt, *prevbezt; uiLayout *layout = pa->layout; uiLayout *col; uiBlock *block; if (!graph_panel_context(C, &ale, &fcu)) return; block = uiLayoutGetBlock(layout); uiBlockSetHandleFunc(block, do_graph_region_buttons, NULL); /* only show this info if there are keyframes to edit */ if (get_active_fcurve_keyframe_edit(fcu, &bezt, &prevbezt)) { PointerRNA bezt_ptr, id_ptr, fcu_prop_ptr; PropertyRNA *fcu_prop = NULL; uiBut *but; int unit = B_UNIT_NONE; /* RNA pointer to keyframe, to allow editing */ RNA_pointer_create(ale->id, &RNA_Keyframe, bezt, &bezt_ptr); /* get property that F-Curve affects, for some unit-conversion magic */ RNA_id_pointer_create(ale->id, &id_ptr); if (RNA_path_resolve(&id_ptr, fcu->rna_path, &fcu_prop_ptr, &fcu_prop) && fcu_prop) { /* determine the unit for this property */ unit = RNA_SUBTYPE_UNIT(RNA_property_subtype(fcu_prop)); } /* interpolation */ col = uiLayoutColumn(layout, FALSE); uiItemR(col, &bezt_ptr, "interpolation", 0, NULL, ICON_NONE); /* numerical coordinate editing * - we use the button-versions of the calls so that we can attach special update handlers * and unit conversion magic that cannot be achieved using a purely RNA-approach */ // XXX: col = uiLayoutColumn(layout, TRUE); /* keyframe itself */ { uiItemL(col, IFACE_("Key:"), ICON_NONE); but = uiDefButR(block, NUM, B_REDR, IFACE_("Frame"), 0, 0, UI_UNIT_X, UI_UNIT_Y, &bezt_ptr, "co", 0, 0, 0, -1, -1, NULL); uiButSetFunc(but, graphedit_activekey_update_cb, fcu, bezt); but = uiDefButR(block, NUM, B_REDR, IFACE_("Value"), 0, 0, UI_UNIT_X, UI_UNIT_Y, &bezt_ptr, "co", 1, 0, 0, -1, -1, NULL); uiButSetFunc(but, graphedit_activekey_update_cb, fcu, bezt); uiButSetUnitType(but, unit); } /* previous handle - only if previous was Bezier interpolation */ if ((prevbezt) && (prevbezt->ipo == BEZT_IPO_BEZ)) { uiItemL(col, IFACE_("Left Handle:"), ICON_NONE); but = uiDefButR(block, NUM, B_REDR, "X", 0, 0, UI_UNIT_X, UI_UNIT_Y, &bezt_ptr, "handle_left", 0, 0, 0, -1, -1, NULL); uiButSetFunc(but, graphedit_activekey_handles_cb, fcu, bezt); but = uiDefButR(block, NUM, B_REDR, "Y", 0, 0, UI_UNIT_X, UI_UNIT_Y, &bezt_ptr, "handle_left", 1, 0, 0, -1, -1, NULL); uiButSetFunc(but, graphedit_activekey_handles_cb, fcu, bezt); uiButSetUnitType(but, unit); } /* next handle - only if current is Bezier interpolation */ if (bezt->ipo == BEZT_IPO_BEZ) { uiItemL(col, IFACE_("Right Handle:"), ICON_NONE); but = uiDefButR(block, NUM, B_REDR, "X", 0, 0, UI_UNIT_X, UI_UNIT_Y, &bezt_ptr, "handle_right", 0, 0, 0, -1, -1, NULL); uiButSetFunc(but, graphedit_activekey_handles_cb, fcu, bezt); but = uiDefButR(block, NUM, B_REDR, "Y", 0, 0, UI_UNIT_X, UI_UNIT_Y, &bezt_ptr, "handle_right", 1, 0, 0, -1, -1, NULL); uiButSetFunc(but, graphedit_activekey_handles_cb, fcu, bezt); uiButSetUnitType(but, unit); } } else { if ((fcu->bezt == NULL) && (fcu->modifiers.first)) { /* modifiers only - so no keyframes to be active */ uiItemL(layout, IFACE_("F-Curve only has F-Modifiers"), ICON_NONE); uiItemL(layout, IFACE_("See Modifiers panel below"), ICON_INFO); } else if (fcu->fpt) { /* samples only */ uiItemL(layout, IFACE_("F-Curve doesn't have any keyframes as it only contains sampled points"), ICON_NONE); } else uiItemL(layout, IFACE_("No active keyframe on F-Curve"), ICON_NONE); } MEM_freeN(ale); }
static char *rna_ColorRampElement_path(PointerRNA *ptr) { PointerRNA ramp_ptr; PropertyRNA *prop; char *path = NULL; int index; /* helper macro for use here to try and get the path * - this calls the standard code for getting a path to a texture... */ #define COLRAMP_GETPATH \ { \ prop = RNA_struct_find_property(&ramp_ptr, "elements"); \ if (prop) { \ index = RNA_property_collection_lookup_index(&ramp_ptr, prop, ptr); \ if (index != -1) { \ char *texture_path = rna_ColorRamp_path(&ramp_ptr); \ path = BLI_sprintfN("%s.elements[%d]", texture_path, index); \ MEM_freeN(texture_path); \ } \ } \ } (void)0 /* determine the path from the ID-block to the ramp */ /* FIXME: this is a very slow way to do it, but it will have to suffice... */ if (ptr->id.data) { ID *id = ptr->id.data; switch (GS(id->name)) { case ID_MA: /* 2 cases for material - diffuse and spec */ { Material *ma = (Material *)id; /* try diffuse first */ if (ma->ramp_col) { RNA_pointer_create(id, &RNA_ColorRamp, ma->ramp_col, &ramp_ptr); COLRAMP_GETPATH; } /* try specular if not diffuse */ if (!path && ma->ramp_spec) { RNA_pointer_create(id, &RNA_ColorRamp, ma->ramp_spec, &ramp_ptr); COLRAMP_GETPATH; } break; } case ID_NT: { bNodeTree *ntree = (bNodeTree *)id; bNode *node; for (node = ntree->nodes.first; node; node = node->next) { if (ELEM(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) { RNA_pointer_create(id, &RNA_ColorRamp, node->storage, &ramp_ptr); COLRAMP_GETPATH; } } break; } case ID_LS: { ListBase listbase; LinkData *link; BKE_linestyle_modifier_list_color_ramps((FreestyleLineStyle *)id, &listbase); for (link = (LinkData *)listbase.first; link; link = link->next) { RNA_pointer_create(id, &RNA_ColorRamp, link->data, &ramp_ptr); COLRAMP_GETPATH; } BLI_freelistN(&listbase); break; } default: /* everything else should have a "color_ramp" property */ { /* create pointer to the ID block, and try to resolve "color_ramp" pointer */ RNA_id_pointer_create(id, &ramp_ptr); if (RNA_path_resolve(&ramp_ptr, "color_ramp", &ramp_ptr, &prop)) { COLRAMP_GETPATH; } break; } } } /* cleanup the macro we defined */ #undef COLRAMP_GETPATH return path; }
/* Write into "name" buffer, the name of the property (retrieved using RNA from the curve's settings), * and return the icon used for the struct that this property refers to * WARNING: name buffer we're writing to cannot exceed 256 chars (check anim_channels_defines.c for details) */ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) { int icon = 0; /* sanity checks */ if (name == NULL) return icon; else if (ELEM3(NULL, id, fcu, fcu->rna_path)) { if (fcu == NULL) strcpy(name, "<invalid>"); else if (fcu->rna_path == NULL) strcpy(name, "<no path>"); else /* id == NULL */ BLI_snprintf(name, 256, "%s[%d]", fcu->rna_path, fcu->array_index); } else { PointerRNA id_ptr, ptr; PropertyRNA *prop; /* get RNA pointer, and resolve the path */ RNA_id_pointer_create(id, &id_ptr); /* try to resolve the path */ if (RNA_path_resolve(&id_ptr, fcu->rna_path, &ptr, &prop)) { const char *structname = NULL, *propname = NULL; char arrayindbuf[16]; const char *arrayname = NULL; short free_structname = 0; /* For now, name will consist of 3 parts: struct-name, property name, array index * There are several options possible: * 1) <struct-name>.<property-name>.<array-index> * i.e. Bone1.Location.X, or Object.Location.X * 2) <array-index> <property-name> (<struct name>) * i.e. X Location (Bone1), or X Location (Object) * * Currently, option 2 is in use, to try and make it easier to quickly identify F-Curves (it does have * problems with looking rather odd though). Option 1 is better in terms of revealing a consistent sense of * hierarchy though, which isn't so clear with option 2. */ /* for structname * - as base, we use a custom name from the structs if one is available * - however, if we're showing subdata of bones (probably there will be other exceptions later) * need to include that info too since it gets confusing otherwise * - if a pointer just refers to the ID-block, then don't repeat this info * since this just introduces clutter */ if (strstr(fcu->rna_path, "bones") && strstr(fcu->rna_path, "constraints")) { /* perform string 'chopping' to get "Bone Name : Constraint Name" */ char *pchanName = BLI_getQuotedStr(fcu->rna_path, "bones["); char *constName = BLI_getQuotedStr(fcu->rna_path, "constraints["); /* assemble the string to display in the UI... */ structname = BLI_sprintfN("%s : %s", pchanName, constName); free_structname = 1; /* free the temp names */ if (pchanName) MEM_freeN(pchanName); if (constName) MEM_freeN(constName); } else if (ptr.data != ptr.id.data) { PropertyRNA *nameprop = RNA_struct_name_property(ptr.type); if (nameprop) { /* this gets a string which will need to be freed */ structname = RNA_property_string_get_alloc(&ptr, nameprop, NULL, 0, NULL); free_structname = 1; } else structname = RNA_struct_ui_name(ptr.type); } /* Property Name is straightforward */ propname = RNA_property_ui_name(prop); /* Array Index - only if applicable */ if (RNA_property_array_length(&ptr, prop)) { char c = RNA_property_array_item_char(prop, fcu->array_index); /* we need to write the index to a temp buffer (in py syntax) */ if (c) BLI_snprintf(arrayindbuf, sizeof(arrayindbuf), "%c ", c); else BLI_snprintf(arrayindbuf, sizeof(arrayindbuf), "[%d]", fcu->array_index); arrayname = &arrayindbuf[0]; } else { /* no array index */ arrayname = ""; } /* putting this all together into the buffer */ // XXX we need to check for invalid names... // XXX the name length limit needs to be passed in or as some define if (structname) BLI_snprintf(name, 256, "%s%s (%s)", arrayname, propname, structname); else BLI_snprintf(name, 256, "%s%s", arrayname, propname); /* free temp name if nameprop is set */ if (free_structname) MEM_freeN((void *)structname); /* Icon for this property's owner: * use the struct's icon if it is set */ icon = RNA_struct_ui_icon(ptr.type); /* valid path - remove the invalid tag since we now know how to use it saving * users manual effort to reenable using "Revive Disabled FCurves" [#29629] */ fcu->flag &= ~FCURVE_DISABLED; } else { /* invalid path */ BLI_snprintf(name, 256, "\"%s[%d]\"", fcu->rna_path, fcu->array_index); /* icon for this should be the icon for the base ID */ // TODO: or should we just use the error icon? icon = RNA_struct_ui_icon(id_ptr.type); /* tag F-Curve as disabled - as not usable path */ fcu->flag |= FCURVE_DISABLED; } } /* return the icon that the active data had */ return icon; }
static int override_remove_button_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); PointerRNA ptr, id_refptr, src; PropertyRNA *prop; int index; const bool all = RNA_boolean_get(op->ptr, "all"); /* try to reset the nominated setting to its default value */ UI_context_active_but_prop_get(C, &ptr, &prop, &index); ID *id = ptr.id.data; IDOverrideStaticProperty *oprop = RNA_property_override_property_find(&ptr, prop); BLI_assert(oprop != NULL); BLI_assert(id != NULL && id->override_static != NULL); const bool is_template = (id->override_static->reference == NULL); /* We need source (i.e. linked data) to restore values of deleted overrides... * If this is an override template, we obviously do not need to restore anything. */ if (!is_template) { RNA_id_pointer_create(id->override_static->reference, &id_refptr); if (!RNA_path_resolve(&id_refptr, oprop->rna_path, &src, NULL)) { BLI_assert(0 && "Failed to create matching source (linked data) RNA pointer"); } } if (!all && index != -1) { bool is_strict_find; /* Remove override operation for given item, * add singular operations for the other items as needed. */ IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find( oprop, NULL, NULL, index, index, false, &is_strict_find); BLI_assert(opop != NULL); if (!is_strict_find) { /* No specific override operation, we have to get generic one, * and create item-specific override operations for all but given index, * before removing generic one. */ for (int idx = RNA_property_array_length(&ptr, prop); idx--;) { if (idx != index) { BKE_override_static_property_operation_get( oprop, opop->operation, NULL, NULL, idx, idx, true, NULL, NULL); } } } BKE_override_static_property_operation_delete(oprop, opop); if (!is_template) { RNA_property_copy(bmain, &ptr, &src, prop, index); } if (BLI_listbase_is_empty(&oprop->operations)) { BKE_override_static_property_delete(id->override_static, oprop); } } else { /* Just remove whole generic override operation of this property. */ BKE_override_static_property_delete(id->override_static, oprop); if (!is_template) { RNA_property_copy(bmain, &ptr, &src, prop, -1); } } return operator_button_property_finish(C, &ptr, prop); }
/* Given a KeyingSet and context info (if required), modify keyframes for the channels specified * by the KeyingSet. This takes into account many of the different combinations of using KeyingSets. * Returns the number of channels that keyframes were added to */ int ANIM_apply_keyingset (bContext *C, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra) { Scene *scene= CTX_data_scene(C); ReportList *reports = CTX_wm_reports(C); KS_Path *ksp; int kflag=0, success= 0; char *groupname= NULL; /* sanity checks */ if (ks == NULL) return 0; /* get flags to use */ if (mode == MODIFYKEY_MODE_INSERT) { /* use KeyingSet's flags as base */ kflag= ks->keyingflag; /* suppliment with info from the context */ kflag |= ANIM_get_keyframing_flags(scene, 1); } else if (mode == MODIFYKEY_MODE_DELETE) kflag= 0; /* if relative Keying Sets, poll and build up the paths */ success = ANIM_validate_keyingset(C, dsources, ks); if (success != 0) { /* return error code if failed */ return success; } /* apply the paths as specified in the KeyingSet now */ for (ksp= ks->paths.first; ksp; ksp= ksp->next) { int arraylen, i; short kflag2; /* skip path if no ID pointer is specified */ if (ksp->id == NULL) { BKE_reportf(reports, RPT_WARNING, "Skipping path in Keying Set, as it has no ID (KS = '%s', Path = '%s'[%d])", ks->name, ksp->rna_path, ksp->array_index); continue; } /* since keying settings can be defined on the paths too, extend the path before using it */ kflag2 = (kflag | ksp->keyingflag); /* get pointer to name of group to add channels to */ if (ksp->groupmode == KSP_GROUP_NONE) groupname= NULL; else if (ksp->groupmode == KSP_GROUP_KSNAME) groupname= ks->name; else groupname= ksp->group; /* init arraylen and i - arraylen should be greater than i so that * normal non-array entries get keyframed correctly */ i= ksp->array_index; arraylen= i; /* get length of array if whole array option is enabled */ if (ksp->flag & KSP_FLAG_WHOLE_ARRAY) { PointerRNA id_ptr, ptr; PropertyRNA *prop; RNA_id_pointer_create(ksp->id, &id_ptr); if (RNA_path_resolve(&id_ptr, ksp->rna_path, &ptr, &prop) && prop) arraylen= RNA_property_array_length(&ptr, prop); } /* we should do at least one step */ if (arraylen == i) arraylen++; /* for each possible index, perform operation * - assume that arraylen is greater than index */ for (; i < arraylen; i++) { /* action to take depends on mode */ if (mode == MODIFYKEY_MODE_INSERT) success += insert_keyframe(reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2); else if (mode == MODIFYKEY_MODE_DELETE) success += delete_keyframe(reports, ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2); } /* set recalc-flags */ switch (GS(ksp->id->name)) { case ID_OB: /* Object (or Object-Related) Keyframes */ { Object *ob= (Object *)ksp->id; ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME; // XXX: only object transforms only? } break; } /* send notifiers for updates (this doesn't require context to work!) */ WM_main_add_notifier(NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); } /* return the number of channels successfully affected */ return success; }
/* Main Driver Management API calls: * Add a new driver for the specified property on the given ID block */ short ANIM_add_driver (ReportList *reports, ID *id, const char rna_path[], int array_index, short flag, int type) { PointerRNA id_ptr, ptr; PropertyRNA *prop; FCurve *fcu; int array_index_max; int done = 0; /* validate pointer first - exit if failure */ RNA_id_pointer_create(id, &id_ptr); if ((RNA_path_resolve(&id_ptr, rna_path, &ptr, &prop) == 0) || (prop == NULL)) { BKE_reportf(reports, RPT_ERROR, "Could not add Driver, as RNA Path is invalid for the given ID (ID = %s, Path = %s)", id->name, rna_path); return 0; } /* key entire array convenience method */ if (array_index == -1) { array_index_max= RNA_property_array_length(&ptr, prop); array_index= 0; } else array_index_max= array_index; /* maximum index should be greater than the start index */ if (array_index == array_index_max) array_index_max += 1; /* will only loop once unless the array index was -1 */ for (; array_index < array_index_max; array_index++) { /* create F-Curve with Driver */ fcu= verify_driver_fcurve(id, rna_path, array_index, 1); if (fcu && fcu->driver) { ChannelDriver *driver= fcu->driver; /* set the type of the driver */ driver->type= type; /* creating drivers for buttons will create the driver(s) with type * "scripted expression" so that their values won't be lost immediately, * so here we copy those values over to the driver's expression */ if (type == DRIVER_TYPE_PYTHON) { PropertyType proptype= RNA_property_type(prop); int array= RNA_property_array_length(&ptr, prop); char *expression= driver->expression; int val, maxlen= sizeof(driver->expression); float fval; if (proptype == PROP_BOOLEAN) { if (!array) val= RNA_property_boolean_get(&ptr, prop); else val= RNA_property_boolean_get_index(&ptr, prop, array_index); BLI_strncpy(expression, (val)? "True": "False", maxlen); } else if (proptype == PROP_INT) { if (!array) val= RNA_property_int_get(&ptr, prop); else val= RNA_property_int_get_index(&ptr, prop, array_index); BLI_snprintf(expression, maxlen, "%d", val); } else if (proptype == PROP_FLOAT) { if (!array) fval= RNA_property_float_get(&ptr, prop); else fval= RNA_property_float_get_index(&ptr, prop, array_index); BLI_snprintf(expression, maxlen, "%.3f", fval); } } /* for easier setup of drivers from UI, a driver variable should be * added if flag is set (UI calls only) */ if (flag & CREATEDRIVER_WITH_DEFAULT_DVAR) { /* assume that users will mostly want this to be of type "Transform Channel" too, * since this allows the easiest setting up of common rig components */ DriverVar *dvar = driver_add_new_variable(driver); driver_change_variable_type(dvar, DVAR_TYPE_TRANSFORM_CHAN); } } /* set the done status */ done += (fcu != NULL); } /* done */ return done; }