Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorJoshua Leung <aligorith@gmail.com>2011-06-29 08:34:20 +0400
committerJoshua Leung <aligorith@gmail.com>2011-06-29 08:34:20 +0400
commit2f60a5030f6c90c2278d3938460809de43012f85 (patch)
treefcf2b78b7a0c1e50cb613ad3219b94d06dc7f406 /source
parentb85e0c3e850b8995577aee9b066e15e66c60bad3 (diff)
Actions can now be made single-user from the Outliner
* Use the same method as from unlinking actions to do this. * Split off the make single-user code used for the ID-browser into a function in blenkernel which can be used elsewhere. Getting materials to also work using this method proved to be a bit too tricky (due to the whole messy ob vs obdata situation), so I haven't done that.
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_library.h3
-rw-r--r--source/blender/blenkernel/intern/action.c88
-rw-r--r--source/blender/blenkernel/intern/library.c28
-rw-r--r--source/blender/editors/interface/interface_templates.c19
-rw-r--r--source/blender/editors/space_outliner/outliner.c115
5 files changed, 175 insertions, 78 deletions
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 871a78bbab3..0d6d41109b4 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -44,6 +44,8 @@ struct Main;
struct Library;
struct wmWindowManager;
struct bContext;
+struct PointerRNA;
+struct PropertyRNA;
void *alloc_libblock(struct ListBase *lb, short type, const char *name);
void *copy_libblock(void *rt);
@@ -53,6 +55,7 @@ void id_lib_extern(struct ID *id);
void id_us_plus(struct ID *id);
void id_us_min(struct ID *id);
int id_make_local(struct ID *id, int test);
+int id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop);
int id_copy(struct ID *id, struct ID **newid, int test);
int id_unlink(struct ID *id, int test);
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 08eed6d61ba..e69ff5df913 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -89,60 +89,80 @@ bAction *add_empty_action(const char name[])
return act;
}
+/* .................................. */
+
+/* temp data for make_local_action */
+typedef struct tMakeLocalActionContext {
+ bAction *act; /* original action */
+ bAction *actn; /* new action */
+
+ int lib; /* some action users were libraries */
+ int local; /* some action users were not libraries */
+} tMakeLocalActionContext;
+
+/* helper function for make_local_action() - local/lib init step */
+static void make_localact_init_cb(ID *id, AnimData *adt, void *mlac_ptr)
+{
+ tMakeLocalActionContext *mlac = (tMakeLocalActionContext *)mlac_ptr;
+
+ if (adt->action == mlac->act) {
+ if (id->lib)
+ mlac->lib = 1;
+ else
+ mlac->local = 1;
+ }
+}
+
+/* helper function for make_local_action() - change references */
+static void make_localact_apply_cb(ID *id, AnimData *adt, void *mlac_ptr)
+{
+ tMakeLocalActionContext *mlac = (tMakeLocalActionContext *)mlac_ptr;
+
+ if (adt->action == mlac->act) {
+ if (id->lib==0) {
+ adt->action = mlac->actn;
+
+ id_us_plus(&mlac->actn->id);
+ id_us_min(&mlac->act->id);
+ }
+ }
+}
+
// does copy_fcurve...
void make_local_action(bAction *act)
{
- // Object *ob;
+ tMakeLocalActionContext mlac = {act, NULL, 0, 0};
Main *bmain= G.main;
- bAction *actn;
- int local=0, lib=0;
- if (act->id.lib==NULL) return;
- if (act->id.us==1) {
+ 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;
}
-#if 0 // XXX old animation system
- ob= G.main->object.first;
- while(ob) {
- if(ob->action==act) {
- if(ob->id.lib) lib= 1;
- else local= 1;
- }
- ob= ob->id.next;
- }
-#endif
+ BKE_animdata_main_cb(bmain, make_localact_init_cb, &mlac);
- if(local && lib==0) {
+ 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(local && lib) {
- actn= copy_action(act);
- actn->id.us= 0;
+ else if (mlac.local && mlac.lib) {
+ mlac.actn= copy_action(act);
+ mlac.actn->id.us= 0;
-#if 0 // XXX old animation system
- ob= G.main->object.first;
- while(ob) {
- if(ob->action==act) {
-
- if(ob->id.lib==0) {
- ob->action = actn;
- actn->id.us++;
- act->id.us--;
- }
- }
- ob= ob->id.next;
- }
-#endif // XXX old animation system
+ BKE_animdata_main_cb(bmain, make_localact_apply_cb, &mlac);
}
}
+/* .................................. */
+
void free_action (bAction *act)
{
/* sanity check */
@@ -161,6 +181,8 @@ void free_action (bAction *act)
BLI_freelistN(&act->markers);
}
+/* .................................. */
+
bAction *copy_action (bAction *src)
{
bAction *dst = NULL;
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 0b07f40cad6..5dbe35b2f7d 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -368,6 +368,34 @@ int id_unlink(ID *id, int test)
return 0;
}
+int id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop)
+{
+ ID *newid = NULL;
+ PointerRNA idptr;
+
+ if (id) {
+ /* if property isn't editable, we're going to have an extra block hanging around until we save */
+ if (RNA_property_editable(ptr, prop)) {
+ if (id_copy(id, &newid, 0) && newid) {
+ /* copy animation actions too */
+ BKE_copy_animdata_id_action(id);
+ /* us is 1 by convention, but RNA_property_pointer_set
+ will also incremement it, so set it to zero */
+ newid->us= 0;
+
+ /* assign copy */
+ RNA_id_pointer_create(newid, &idptr);
+ RNA_property_pointer_set(ptr, prop, idptr);
+ RNA_property_update(C, ptr, prop);
+
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
ListBase *which_libbase(Main *mainlib, short type)
{
switch( type ) {
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 32a20e82d2f..39abcecbb6b 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -234,7 +234,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
{
TemplateID *template= (TemplateID*)arg_litem;
PointerRNA idptr= RNA_property_pointer_get(&template->ptr, template->prop);
- ID *id= idptr.data, *newid;
+ ID *id= idptr.data;
int event= GET_INT_FROM_POINTER(arg_event);
switch(event) {
@@ -273,21 +273,8 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
}
break;
case UI_ID_ALONE:
- if(id) {
- /* make copy */
- if(id_copy(id, &newid, 0) && newid) {
- /* copy animation actions too */
- BKE_copy_animdata_id_action(id);
- /* us is 1 by convention, but RNA_property_pointer_set
- will also incremement it, so set it to zero */
- newid->us= 0;
-
- /* assign copy */
- RNA_id_pointer_create(newid, &idptr);
- RNA_property_pointer_set(&template->ptr, template->prop, idptr);
- RNA_property_update(C, &template->ptr, template->prop);
- }
- }
+ if(id)
+ id_single_user(C, id, &template->ptr, template->prop);
break;
#if 0
case UI_ID_AUTO_NAME:
diff --git a/source/blender/editors/space_outliner/outliner.c b/source/blender/editors/space_outliner/outliner.c
index 20be507f5a0..3e4641bc0b9 100644
--- a/source/blender/editors/space_outliner/outliner.c
+++ b/source/blender/editors/space_outliner/outliner.c
@@ -3340,6 +3340,23 @@ static void id_local_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *
}
}
+
+static void singleuser_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tsep, TreeStoreElem *tselem)
+{
+ ID *id = tselem->id;
+
+ if (id) {
+ IdAdtTemplate *iat = (IdAdtTemplate *)tsep->id;
+ PointerRNA ptr = {{0}};
+ PropertyRNA *prop;
+
+ RNA_pointer_create(&iat->id, &RNA_AnimData, iat->adt, &ptr);
+ prop = RNA_struct_find_property(&ptr, "action");
+
+ id_single_user(C, id, &ptr, prop);
+ }
+}
+
static void group_linkobs2scene_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
{
Group *group= (Group *)tselem->id;
@@ -3634,10 +3651,18 @@ void OUTLINER_OT_group_operation(wmOperatorType *ot)
/* **************************************** */
+typedef enum eOutlinerIdOpTypes {
+ OUTLINER_IDOP_INVALID = 0,
+ OUTLINER_IDOP_UNLINK,
+ OUTLINER_IDOP_LOCAL,
+ OUTLINER_IDOP_SINGLE
+} eOutlinerIdOpTypes;
+
// TODO: implement support for changing the ID-block used
static EnumPropertyItem prop_id_op_types[] = {
- {1, "UNLINK", 0, "Unlink", ""},
- {2, "LOCAL", 0, "Make Local", ""},
+ {OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""},
+ {OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""},
+ {OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -3646,7 +3671,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
Scene *scene= CTX_data_scene(C);
SpaceOops *soops= CTX_wm_space_outliner(C);
int scenelevel=0, objectlevel=0, idlevel=0, datalevel=0;
- int event;
+ eOutlinerIdOpTypes event;
/* check for invalid states */
if (soops == NULL)
@@ -3656,33 +3681,65 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op)
event= RNA_enum_get(op->ptr, "type");
- if(event==1) {
- switch(idlevel) {
- case ID_AC:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_action_cb);
-
- WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL);
- ED_undo_push(C, "Unlink action");
- break;
- case ID_MA:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_material_cb);
-
- WM_event_add_notifier(C, NC_OBJECT|ND_OB_SHADING, NULL);
- ED_undo_push(C, "Unlink material");
- break;
- case ID_TE:
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_texture_cb);
-
- WM_event_add_notifier(C, NC_OBJECT|ND_OB_SHADING, NULL);
- ED_undo_push(C, "Unlink texture");
- break;
- default:
- BKE_report(op->reports, RPT_WARNING, "Not Yet");
+ switch (event) {
+ case OUTLINER_IDOP_UNLINK:
+ {
+ /* unlink datablock from its parent */
+ switch (idlevel) {
+ case ID_AC:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_action_cb);
+
+ WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL);
+ ED_undo_push(C, "Unlink action");
+ break;
+ case ID_MA:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_material_cb);
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_OB_SHADING, NULL);
+ ED_undo_push(C, "Unlink material");
+ break;
+ case ID_TE:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_texture_cb);
+
+ WM_event_add_notifier(C, NC_OBJECT|ND_OB_SHADING, NULL);
+ ED_undo_push(C, "Unlink texture");
+ break;
+ default:
+ BKE_report(op->reports, RPT_WARNING, "Not Yet");
+ break;
+ }
}
- }
- else if(event==2) {
- outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb);
- ED_undo_push(C, "Localized Data");
+ break;
+
+ case OUTLINER_IDOP_LOCAL:
+ {
+ /* make local */
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb);
+ ED_undo_push(C, "Localized Data");
+ }
+ break;
+
+ case OUTLINER_IDOP_SINGLE:
+ {
+ /* make single user */
+ switch (idlevel) {
+ case ID_AC:
+ outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_action_cb);
+
+ WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL);
+ ED_undo_push(C, "Single-User Action");
+ break;
+
+ default:
+ BKE_report(op->reports, RPT_WARNING, "Not Yet");
+ break;
+ }
+ }
+ break;
+
+ default:
+ // invalid - unhandled
+ break;
}
/* wrong notifier still... */