// does copy_fcurve... void make_local_action(bAction *act) { tMakeLocalActionContext mlac = {act, NULL, 0, 0}; Main *bmain= G.main; if (act->id.lib==NULL) return; // XXX: double-check this; it used to be just single-user check, but that was when fake-users were still default if ((act->id.flag & LIB_FAKEUSER) && (act->id.us<=1)) { act->id.lib= NULL; act->id.flag= LIB_LOCAL; new_id(&bmain->action, (ID *)act, NULL); return; } BKE_animdata_main_cb(bmain, make_localact_init_cb, &mlac); if (mlac.local && mlac.lib==0) { act->id.lib= NULL; act->id.flag= LIB_LOCAL; //make_local_action_channels(act); new_id(&bmain->action, (ID *)act, NULL); } else if (mlac.local && mlac.lib) { mlac.actn= copy_action(act); mlac.actn->id.us= 0; BKE_animdata_main_cb(bmain, make_localact_apply_cb, &mlac); } }
static int act_new_exec(bContext *C, wmOperator *UNUSED(op)) { PointerRNA ptr, idptr; PropertyRNA *prop; /* hook into UI */ uiIDContextProperty(C, &ptr, &prop); if (prop) { bAction *action=NULL, *oldact=NULL; PointerRNA oldptr; /* create action - the way to do this depends on whether we've got an * existing one there already, in which case we make a copy of it * (which is useful for "versioning" actions within the same file) */ oldptr = RNA_property_pointer_get(&ptr, prop); oldact = (bAction *)oldptr.id.data; if (oldact && GS(oldact->id.name)==ID_AC) { /* make a copy of the existing action */ action= copy_action(oldact); } else { /* just make a new (empty) action */ action= add_empty_action("Action"); } /* when creating new ID blocks, use is already 1 (fake user), * but RNA pointer use also increases user, so this compensates it */ action->id.us--; RNA_id_pointer_create(&action->id, &idptr); RNA_property_pointer_set(&ptr, prop, idptr); RNA_property_update(C, &ptr, prop); } /* set notifier that keyframes have changed */ WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_EDITED, NULL); return OPERATOR_FINISHED; }
int id_copy(ID *id, ID **newid, int test) { if(!test) *newid= NULL; /* conventions: * - make shallow copy, only this ID block * - id.us of the new ID is set to 1 */ switch(GS(id->name)) { case ID_SCE: return 0; /* can't be copied from here */ case ID_LI: return 0; /* can't be copied from here */ case ID_OB: if(!test) *newid= (ID*)copy_object((Object*)id); return 1; case ID_ME: if(!test) *newid= (ID*)copy_mesh((Mesh*)id); return 1; case ID_CU: if(!test) *newid= (ID*)copy_curve((Curve*)id); return 1; case ID_MB: if(!test) *newid= (ID*)copy_mball((MetaBall*)id); return 1; case ID_MA: if(!test) *newid= (ID*)copy_material((Material*)id); return 1; case ID_TE: if(!test) *newid= (ID*)copy_texture((Tex*)id); return 1; case ID_IM: if(!test) *newid= (ID*)copy_image((Image*)id); return 1; case ID_LT: if(!test) *newid= (ID*)copy_lattice((Lattice*)id); return 1; case ID_LA: if(!test) *newid= (ID*)copy_lamp((Lamp*)id); return 1; case ID_SPK: if(!test) *newid= (ID*)copy_speaker((Speaker*)id); return 1; case ID_CA: if(!test) *newid= (ID*)copy_camera((Camera*)id); return 1; case ID_IP: return 0; /* deprecated */ case ID_KE: if(!test) *newid= (ID*)copy_key((Key*)id); return 1; case ID_WO: if(!test) *newid= (ID*)copy_world((World*)id); return 1; case ID_SCR: return 0; /* can't be copied from here */ case ID_VF: return 0; /* not implemented */ case ID_TXT: if(!test) *newid= (ID*)copy_text((Text*)id); return 1; case ID_SCRIPT: return 0; /* deprecated */ case ID_SO: return 0; /* not implemented */ case ID_GR: if(!test) *newid= (ID*)copy_group((Group*)id); return 1; case ID_AR: if(!test) *newid= (ID*)copy_armature((bArmature*)id); return 1; case ID_AC: if(!test) *newid= (ID*)copy_action((bAction*)id); return 1; case ID_NT: if(!test) *newid= (ID*)ntreeCopyTree((bNodeTree*)id); return 1; case ID_BR: if(!test) *newid= (ID*)copy_brush((Brush*)id); return 1; case ID_PA: if(!test) *newid= (ID*)psys_copy_settings((ParticleSettings*)id); return 1; case ID_WM: return 0; /* can't be copied from here */ case ID_GD: return 0; /* not implemented */ } return 0; }
/* returns 1 if its OK */ int node_group_ungroup(bNodeTree *ntree, bNode *gnode) { bNodeLink *link, *linkn; bNode *node, *nextn; bNodeTree *ngroup, *wgroup; ListBase anim_basepaths = {NULL, NULL}; ngroup= (bNodeTree *)gnode->id; if(ngroup==NULL) return 0; /* clear new pointers, set in copytree */ for(node= ntree->nodes.first; node; node= node->next) node->new_node= NULL; /* wgroup is a temporary copy of the NodeTree we're merging in * - all of wgroup's nodes are transferred across to their new home * - ngroup (i.e. the source NodeTree) is left unscathed */ wgroup= ntreeCopyTree(ngroup); /* add the nodes into the ntree */ for(node= wgroup->nodes.first; node; node= nextn) { nextn= node->next; /* keep track of this node's RNA "base" path (the part of the pat identifying the node) * if the old nodetree has animation data which potentially covers this node */ if (wgroup->adt) { PointerRNA ptr; char *path; RNA_pointer_create(&wgroup->id, &RNA_Node, node, &ptr); path = RNA_path_from_ID_to_struct(&ptr); if (path) BLI_addtail(&anim_basepaths, BLI_genericNodeN(path)); } /* migrate node */ BLI_remlink(&wgroup->nodes, node); BLI_addtail(&ntree->nodes, node); node->locx+= gnode->locx; node->locy+= gnode->locy; node->flag |= NODE_SELECT; } /* restore external links to and from the gnode */ for(link= ntree->links.first; link; link= link->next) { if (link->fromnode==gnode) { if (link->fromsock->groupsock) { bNodeSocket *gsock= link->fromsock->groupsock; if (gsock->link) { if (gsock->link->fromnode) { /* NB: using the new internal copies here! the groupsock pointer still maps to the old tree */ link->fromnode = (gsock->link->fromnode ? gsock->link->fromnode->new_node : NULL); link->fromsock = gsock->link->fromsock->new_sock; } else { /* group output directly maps to group input */ bNodeSocket *insock= node_group_find_input(gnode, gsock->link->fromsock); if (insock->link) { link->fromnode = insock->link->fromnode; link->fromsock = insock->link->fromsock; } } } else { /* copy the default input value from the group socket default to the external socket */ convert_socket_value(gsock, link->tosock); } } } } /* remove internal output links, these are not used anymore */ for(link=wgroup->links.first; link; link= linkn) { linkn = link->next; if (!link->tonode) nodeRemLink(wgroup, link); } /* restore links from internal nodes */ for(link= wgroup->links.first; link; link= link->next) { /* indicates link to group input */ if (!link->fromnode) { /* NB: can't use find_group_node_input here, * because gnode sockets still point to the old tree! */ bNodeSocket *insock; for (insock= gnode->inputs.first; insock; insock= insock->next) if (insock->groupsock->new_sock == link->fromsock) break; if (insock->link) { link->fromnode = insock->link->fromnode; link->fromsock = insock->link->fromsock; } else { /* copy the default input value from the group node socket default to the internal socket */ convert_socket_value(insock, link->tosock); nodeRemLink(wgroup, link); } } } /* add internal links to the ntree */ for(link= wgroup->links.first; link; link= linkn) { linkn= link->next; BLI_remlink(&wgroup->links, link); BLI_addtail(&ntree->links, link); } /* and copy across the animation */ if (wgroup->adt) { LinkData *ld, *ldn=NULL; bAction *waction; /* firstly, wgroup needs to temporary dummy action that can be destroyed, as it shares copies */ waction = wgroup->adt->action = copy_action(wgroup->adt->action); /* now perform the moving */ BKE_animdata_separate_by_basepath(&wgroup->id, &ntree->id, &anim_basepaths); /* paths + their wrappers need to be freed */ for (ld = anim_basepaths.first; ld; ld = ldn) { ldn = ld->next; MEM_freeN(ld->data); BLI_freelinkN(&anim_basepaths, ld); } /* free temp action too */ free_libblock(&G.main->action, waction); } /* delete the group instance. this also removes old input links! */ nodeFreeNode(ntree, gnode); /* free the group tree (takes care of user count) */ free_libblock(&G.main->nodetree, wgroup); ntree->update |= NTREE_UPDATE_NODES|NTREE_UPDATE_LINKS; ntreeUpdateTree(ntree); return 1; }