Make Links (Ctrl+L) back
- split into 2 operators: object.make_links_data() & object.make_links_scene since they are quite different. - added reusable functions RNA_group_itemf & RNA_scene_itemf which can be used for any operator that takes ID data (easy to add more types Mesh, Text etc) - DummyRNA_NULL_items for dynamic items so each operator need not define its own empty enum.
This commit is contained in:
parent
b221e57fd2
commit
46c8bfe151
@ -479,8 +479,10 @@ class VIEW3D_MT_object(bpy.types.Menu):
|
||||
layout.item_booleanO("object.duplicate", "linked", True, text="Duplicate Linked")
|
||||
layout.itemO("object.delete", text="Delete...")
|
||||
layout.itemO("object.proxy_make", text="Make Proxy...")
|
||||
layout.itemM("VIEW3D_MT_make_links", text="Make Links...")
|
||||
layout.item_menu_enumO("object.make_local", "type", text="Make Local...")
|
||||
layout.itemM("VIEW3D_MT_make_single_user")
|
||||
layout.itemM("VIEW3D_MT_make_links")
|
||||
|
||||
layout.itemS()
|
||||
|
||||
@ -604,6 +606,18 @@ class VIEW3D_MT_make_single_user(bpy.types.Menu):
|
||||
props = layout.itemO("object.make_single_user", properties=True, text="Animation")
|
||||
props.animation = True
|
||||
|
||||
|
||||
class VIEW3D_MT_make_links(bpy.types.Menu):
|
||||
bl_label = "Make Links"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.item_menu_enumO("object.make_links_scene", "type", text="Objects to Scene...")
|
||||
|
||||
layout.items_enumO("object.make_links_data", property="type") # inline
|
||||
|
||||
|
||||
# ********** Vertex paint menu **********
|
||||
|
||||
|
||||
@ -1600,6 +1614,7 @@ bpy.types.register(VIEW3D_MT_object_group)
|
||||
bpy.types.register(VIEW3D_MT_object_constraints)
|
||||
bpy.types.register(VIEW3D_MT_object_showhide)
|
||||
bpy.types.register(VIEW3D_MT_make_single_user)
|
||||
bpy.types.register(VIEW3D_MT_make_links)
|
||||
|
||||
|
||||
bpy.types.register(VIEW3D_MT_sculpt) # Sculpt Menu
|
||||
|
@ -678,31 +678,8 @@ void OBJECT_OT_lamp_add(wmOperatorType *ot)
|
||||
ED_object_add_generic_props(ot, FALSE);
|
||||
}
|
||||
|
||||
/* add dupligroup */
|
||||
static EnumPropertyItem *add_dupligroup_itemf(bContext *C, PointerRNA *ptr, int *free)
|
||||
{
|
||||
EnumPropertyItem *item= NULL, item_tmp;
|
||||
int totitem= 0;
|
||||
int i= 0;
|
||||
Group *group;
|
||||
|
||||
memset(&item_tmp, 0, sizeof(item_tmp));
|
||||
|
||||
for(group= CTX_data_main(C)->group.first; group; group= group->id.next) {
|
||||
item_tmp.identifier= item_tmp.name= group->id.name+2;
|
||||
item_tmp.value= i++;
|
||||
RNA_enum_item_add(&item, &totitem, &item_tmp);
|
||||
}
|
||||
|
||||
RNA_enum_item_end(&item, &totitem);
|
||||
*free= 1;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
static int group_instance_add_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
/* XXX, using an enum for library lookups is a bit dodgy */
|
||||
Group *group= BLI_findlink(&CTX_data_main(C)->group, RNA_enum_get(op->ptr, "type"));
|
||||
|
||||
int view_align, enter_editmode;
|
||||
@ -728,9 +705,6 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
|
||||
void OBJECT_OT_group_instance_add(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
static EnumPropertyItem prop_group_dummy_types[] = {
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
/* identifiers */
|
||||
ot->name= "Add Group Instance";
|
||||
@ -746,8 +720,8 @@ void OBJECT_OT_group_instance_add(wmOperatorType *ot)
|
||||
ot->flag= 0;
|
||||
|
||||
/* properties */
|
||||
prop= RNA_def_enum(ot->srna, "type", prop_group_dummy_types, 0, "Type", "");
|
||||
RNA_def_enum_funcs(prop, add_dupligroup_itemf);
|
||||
prop= RNA_def_enum(ot->srna, "type", DummyRNA_NULL_items, 0, "Type", "");
|
||||
RNA_def_enum_funcs(prop, RNA_group_itemf);
|
||||
ED_object_add_generic_props(ot, FALSE);
|
||||
}
|
||||
|
||||
|
@ -60,6 +60,8 @@ void OBJECT_OT_slow_parent_set(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_slow_parent_clear(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_make_local(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_make_single_user(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_make_links_scene(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_make_links_data(struct wmOperatorType *ot);
|
||||
void OBJECT_OT_move_to_layer(struct wmOperatorType *ot);
|
||||
|
||||
/* object_edit.c */
|
||||
|
@ -92,6 +92,8 @@ void ED_operatortypes_object(void)
|
||||
WM_operatortype_append(OBJECT_OT_slow_parent_clear);
|
||||
WM_operatortype_append(OBJECT_OT_make_local);
|
||||
WM_operatortype_append(OBJECT_OT_make_single_user);
|
||||
WM_operatortype_append(OBJECT_OT_make_links_scene);
|
||||
WM_operatortype_append(OBJECT_OT_make_links_data);
|
||||
WM_operatortype_append(OBJECT_OT_move_to_layer);
|
||||
|
||||
WM_operatortype_append(OBJECT_OT_select_inverse);
|
||||
@ -290,6 +292,9 @@ void ED_keymap_object(wmKeyConfig *keyconf)
|
||||
|
||||
kmi= WM_keymap_add_item(keymap, "WM_OT_call_menu", UKEY, KM_PRESS, 0, 0);
|
||||
RNA_string_set(kmi->ptr, "name", "VIEW3D_MT_make_single_user");
|
||||
|
||||
kmi= WM_keymap_add_item(keymap, "WM_OT_call_menu", LKEY, KM_PRESS, KM_CTRL, 0);
|
||||
RNA_string_set(kmi->ptr, "name", "VIEW3D_MT_make_links");
|
||||
|
||||
WM_keymap_add_item(keymap, "OBJECT_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
|
||||
WM_keymap_add_item(keymap, "OBJECT_OT_duplicate_move_linked", DKEY, KM_PRESS, KM_ALT, 0);
|
||||
|
@ -72,6 +72,7 @@
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_sca.h"
|
||||
#include "BKE_scene.h"
|
||||
#include "BKE_texture.h"
|
||||
#include "BKE_utildefines.h"
|
||||
|
||||
@ -83,6 +84,7 @@
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
#include "RNA_enum_types.h"
|
||||
|
||||
#include "ED_anim_api.h"
|
||||
#include "ED_armature.h"
|
||||
@ -92,10 +94,6 @@
|
||||
|
||||
#include "object_intern.h"
|
||||
|
||||
/* ************* XXX **************** */
|
||||
static int pupmenu(const char *msg) {return 0;}
|
||||
static int pupmenu_col(const char *msg, int val) {return 0;}
|
||||
|
||||
/*********************** Make Vertex Parent Operator ************************/
|
||||
|
||||
static int vertex_parent_set_poll(bContext *C)
|
||||
@ -1132,97 +1130,77 @@ void link_to_scene(unsigned short nr)
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void make_links(bContext *C, wmOperator *op, Scene *scene, View3D *v3d, short event)
|
||||
static int make_links_scene_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *ob, *obt;
|
||||
Base *base, *nbase, *sbase;
|
||||
Scene *sce = NULL;
|
||||
ID *id;
|
||||
int a;
|
||||
short nr=0;
|
||||
char *strp;
|
||||
Scene *scene_to= BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "type"));
|
||||
|
||||
if(!(ob=OBACT)) return;
|
||||
|
||||
if(event==1) {
|
||||
IDnames_to_pupstring(&strp, NULL, NULL, &(G.main->scene), 0, &nr);
|
||||
|
||||
if(nr == -2) {
|
||||
MEM_freeN(strp);
|
||||
|
||||
// XXX activate_databrowse((ID *)scene, ID_SCE, 0, B_INFOSCE, &(G.curscreen->scenenr), link_to_scene );
|
||||
|
||||
return;
|
||||
}
|
||||
else {
|
||||
event= pupmenu_col(strp, 20);
|
||||
MEM_freeN(strp);
|
||||
|
||||
if(event<= 0) return;
|
||||
|
||||
nr= 1;
|
||||
sce= G.main->scene.first;
|
||||
while(sce) {
|
||||
if(nr==event) break;
|
||||
nr++;
|
||||
sce= sce->id.next;
|
||||
}
|
||||
if(sce==scene) {
|
||||
BKE_report(op->reports, RPT_ERROR, "This is the current scene");
|
||||
return;
|
||||
}
|
||||
if(sce==0 || sce->id.lib) return;
|
||||
|
||||
/* remember: is needed below */
|
||||
event= 1;
|
||||
}
|
||||
if(scene_to==NULL) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Scene not found");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* All non group linking */
|
||||
for(base= FIRSTBASE; base; base= base->next) {
|
||||
if(event==1 || base != BASACT) {
|
||||
|
||||
obt= base->object;
|
||||
if(scene_to == CTX_data_scene(C)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Can't link objects into the same scene");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if(TESTBASE(v3d, base)) {
|
||||
|
||||
if(event==1) { /* to scene */
|
||||
|
||||
/* test if already linked */
|
||||
sbase= sce->base.first;
|
||||
while(sbase) {
|
||||
if(sbase->object==base->object) break;
|
||||
sbase= sbase->next;
|
||||
}
|
||||
if(sbase) { /* remove */
|
||||
continue;
|
||||
}
|
||||
|
||||
nbase= MEM_mallocN( sizeof(Base), "newbase");
|
||||
*nbase= *base;
|
||||
BLI_addhead( &(sce->base), nbase);
|
||||
id_us_plus((ID *)base->object);
|
||||
CTX_DATA_BEGIN(C, Base*, base, selected_bases)
|
||||
{
|
||||
if(!object_in_scene(base->object, scene_to)) {
|
||||
Base *nbase= MEM_mallocN( sizeof(Base), "newbase");
|
||||
*nbase= *base;
|
||||
BLI_addhead( &(scene_to->base), nbase);
|
||||
id_us_plus((ID *)base->object);
|
||||
}
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
ED_anim_dag_flush_update(C);
|
||||
|
||||
/* one day multiple scenes will be visible, then we should have some update function for them */
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
enum {
|
||||
MAKE_LINKS_OBDATA = 1,
|
||||
MAKE_LINKS_MATERIALS,
|
||||
MAKE_LINKS_ANIMDATA,
|
||||
MAKE_LINKS_DUPLIGROUP,
|
||||
};
|
||||
|
||||
static int make_links_data_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
int event = RNA_int_get(op->ptr, "type");
|
||||
Object *ob;
|
||||
ID *id;
|
||||
int a;
|
||||
|
||||
ob= CTX_data_active_object(C);
|
||||
|
||||
CTX_DATA_BEGIN(C, Object*, obt, selected_editable_objects) {
|
||||
if(ob != obt) {
|
||||
switch(event) {
|
||||
case MAKE_LINKS_OBDATA: /* obdata */
|
||||
id= obt->data;
|
||||
id->us--;
|
||||
|
||||
id= ob->data;
|
||||
id_us_plus(id);
|
||||
obt->data= id;
|
||||
|
||||
/* if amount of material indices changed: */
|
||||
test_object_materials(obt->data);
|
||||
|
||||
obt->recalc |= OB_RECALC_DATA;
|
||||
break;
|
||||
case MAKE_LINKS_MATERIALS:
|
||||
/* new approach, using functions from kernel */
|
||||
for(a=0; a<ob->totcol; a++) {
|
||||
Material *ma= give_current_material(ob, a+1);
|
||||
assign_material(obt, ma, a+1); /* also works with ma==NULL */
|
||||
}
|
||||
}
|
||||
if(TESTBASELIB(v3d, base)) {
|
||||
if(event==2 || event==5) { /* obdata */
|
||||
if(ob->type==obt->type) {
|
||||
|
||||
id= obt->data;
|
||||
id->us--;
|
||||
|
||||
id= ob->data;
|
||||
id_us_plus(id);
|
||||
obt->data= id;
|
||||
|
||||
/* if amount of material indices changed: */
|
||||
test_object_materials(obt->data);
|
||||
|
||||
obt->recalc |= OB_RECALC_DATA;
|
||||
}
|
||||
}
|
||||
else if(event==4) { /* ob ipo */
|
||||
break;
|
||||
case MAKE_LINKS_ANIMDATA:
|
||||
#if 0 // XXX old animation system
|
||||
if(obt->ipo) obt->ipo->id.us--;
|
||||
obt->ipo= ob->ipo;
|
||||
@ -1231,67 +1209,75 @@ void make_links(bContext *C, wmOperator *op, Scene *scene, View3D *v3d, short ev
|
||||
do_ob_ipo(scene, obt);
|
||||
}
|
||||
#endif // XXX old animation system
|
||||
break;
|
||||
case MAKE_LINKS_DUPLIGROUP:
|
||||
if(ob->dup_group) ob->dup_group->id.us--;
|
||||
obt->dup_group= ob->dup_group;
|
||||
if(obt->dup_group) {
|
||||
id_us_plus((ID *)obt->dup_group);
|
||||
obt->transflag |= OB_DUPLIGROUP;
|
||||
}
|
||||
else if(event==6) {
|
||||
if(ob->dup_group) ob->dup_group->id.us--;
|
||||
obt->dup_group= ob->dup_group;
|
||||
if(obt->dup_group) {
|
||||
id_us_plus((ID *)obt->dup_group);
|
||||
obt->transflag |= OB_DUPLIGROUP;
|
||||
}
|
||||
}
|
||||
else if(event==3) { /* materials */
|
||||
|
||||
/* new approach, using functions from kernel */
|
||||
for(a=0; a<ob->totcol; a++) {
|
||||
Material *ma= give_current_material(ob, a+1);
|
||||
assign_material(obt, ma, a+1); /* also works with ma==NULL */
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ED_anim_dag_flush_update(C);
|
||||
CTX_DATA_END;
|
||||
|
||||
ED_anim_dag_flush_update(C);
|
||||
WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, CTX_wm_view3d(C));
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void make_links_menu(bContext *C, Scene *scene, View3D *v3d)
|
||||
|
||||
void OBJECT_OT_make_links_scene(wmOperatorType *ot)
|
||||
{
|
||||
Object *ob;
|
||||
short event=0;
|
||||
char str[140];
|
||||
|
||||
if(!(ob=OBACT)) return;
|
||||
|
||||
strcpy(str, "Make Links %t|To Scene...%x1|%l|Object Ipo%x4");
|
||||
|
||||
if(ob->type==OB_MESH)
|
||||
strcat(str, "|Mesh Data%x2|Materials%x3");
|
||||
else if(ob->type==OB_CURVE)
|
||||
strcat(str, "|Curve Data%x2|Materials%x3");
|
||||
else if(ob->type==OB_FONT)
|
||||
strcat(str, "|Text Data%x2|Materials%x3");
|
||||
else if(ob->type==OB_SURF)
|
||||
strcat(str, "|Surface Data%x2|Materials%x3");
|
||||
else if(ob->type==OB_MBALL)
|
||||
strcat(str, "|Materials%x3");
|
||||
else if(ob->type==OB_CAMERA)
|
||||
strcat(str, "|Camera Data%x2");
|
||||
else if(ob->type==OB_LAMP)
|
||||
strcat(str, "|Lamp Data%x2");
|
||||
else if(ob->type==OB_LATTICE)
|
||||
strcat(str, "|Lattice Data%x2");
|
||||
else if(ob->type==OB_ARMATURE)
|
||||
strcat(str, "|Armature Data%x2");
|
||||
|
||||
event= pupmenu(str);
|
||||
|
||||
if(event<= 0) return;
|
||||
|
||||
make_links(C, NULL, scene, v3d, event);
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* identifiers */
|
||||
ot->name= "Link Objects to Scene";
|
||||
ot->description = "Make linked data local to each object.";
|
||||
ot->idname= "OBJECT_OT_make_links_scene";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec= make_links_scene_exec;
|
||||
/* better not run the poll check */
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
prop= RNA_def_enum(ot->srna, "type", DummyRNA_NULL_items, 0, "Type", "");
|
||||
RNA_def_enum_funcs(prop, RNA_scene_itemf);
|
||||
}
|
||||
|
||||
void OBJECT_OT_make_links_data(wmOperatorType *ot)
|
||||
{
|
||||
static EnumPropertyItem make_links_items[]= {
|
||||
{MAKE_LINKS_OBDATA, "OBDATA", 0, "Object Data", ""},
|
||||
{MAKE_LINKS_MATERIALS, "MATERIAL", 0, "Materials", ""},
|
||||
{MAKE_LINKS_ANIMDATA, "ANIMATION", 0, "Animation Data", ""},
|
||||
{MAKE_LINKS_DUPLIGROUP, "DUPLIGROUP", 0, "DupliGroup", ""},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* identifiers */
|
||||
ot->name= "Link Data";
|
||||
ot->description = "Make links from the active object to other selected objects.";
|
||||
ot->idname= "OBJECT_OT_make_links_data";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec= make_links_data_exec;
|
||||
ot->poll= ED_operator_scene_editable;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
prop= RNA_def_enum(ot->srna, "type", make_links_items, 0, "Type", "");
|
||||
}
|
||||
|
||||
|
||||
/**************************** Make Single User ********************************/
|
||||
|
||||
static void single_object_users__forwardModifierLinks(void *userData, Object *ob, Object **obpoin)
|
||||
|
@ -31,6 +31,8 @@
|
||||
|
||||
extern EnumPropertyItem id_type_items[];
|
||||
|
||||
/* use in cases where only dynamic types are used */
|
||||
extern EnumPropertyItem DummyRNA_NULL_items[];
|
||||
|
||||
extern EnumPropertyItem object_mode_items[];
|
||||
|
||||
@ -69,6 +71,11 @@ struct bContext;
|
||||
struct PointerRNA;
|
||||
EnumPropertyItem *rna_TransformOrientation_itemf(struct bContext *C, struct PointerRNA *ptr, int *free);
|
||||
|
||||
/* Generic functions, return an enum from library data, index is the position
|
||||
* in the linked list can add more for different types as needed */
|
||||
EnumPropertyItem *RNA_group_itemf(struct bContext *C, struct PointerRNA *ptr, int *free);
|
||||
EnumPropertyItem *RNA_scene_itemf(struct bContext *C, struct PointerRNA *ptr, int *free);
|
||||
|
||||
#endif /* RNA_ENUM_TYPES */
|
||||
|
||||
|
||||
|
@ -734,6 +734,11 @@ StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop)
|
||||
return &RNA_UnknownType;
|
||||
}
|
||||
|
||||
/* Reuse for dynamic types */
|
||||
EnumPropertyItem DummyRNA_NULL_items[] = {
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
void RNA_property_enum_items(bContext *C, PointerRNA *ptr, PropertyRNA *prop, EnumPropertyItem **item, int *totitem, int *free)
|
||||
{
|
||||
EnumPropertyRNA *eprop= (EnumPropertyRNA*)rna_ensure_property(prop);
|
||||
|
@ -2446,3 +2446,33 @@ void wm_window_keymap(wmKeyConfig *keyconf)
|
||||
RNA_string_set(km->ptr, "value", "DOPESHEET_EDITOR");
|
||||
}
|
||||
|
||||
/* Generic itemf's for operators that take library args */
|
||||
static EnumPropertyItem *rna_id_itemf(bContext *C, PointerRNA *ptr, int *free, ID *id)
|
||||
{
|
||||
EnumPropertyItem *item= NULL, item_tmp;
|
||||
int totitem= 0;
|
||||
int i= 0;
|
||||
|
||||
memset(&item_tmp, 0, sizeof(item_tmp));
|
||||
|
||||
for( ; id; id= id->next) {
|
||||
item_tmp.identifier= item_tmp.name= id->name+2;
|
||||
item_tmp.value= i++;
|
||||
RNA_enum_item_add(&item, &totitem, &item_tmp);
|
||||
}
|
||||
|
||||
RNA_enum_item_end(&item, &totitem);
|
||||
*free= 1;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/* can add more */
|
||||
EnumPropertyItem *RNA_group_itemf(bContext *C, PointerRNA *ptr, int *free)
|
||||
{
|
||||
rna_id_itemf(C, ptr, free, (ID *)CTX_data_main(C)->group.first);
|
||||
}
|
||||
EnumPropertyItem *RNA_scene_itemf(bContext *C, PointerRNA *ptr, int *free)
|
||||
{
|
||||
rna_id_itemf(C, ptr, free, (ID *)CTX_data_main(C)->scene.first);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user