Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_outliner/outliner_tools.c
| Show First 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
| #include "DNA_object_types.h" | #include "DNA_object_types.h" | ||||
| #include "DNA_constraint_types.h" | #include "DNA_constraint_types.h" | ||||
| #include "DNA_modifier_types.h" | #include "DNA_modifier_types.h" | ||||
| #include "BLI_blenlib.h" | #include "BLI_blenlib.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BKE_animsys.h" | #include "BKE_animsys.h" | ||||
| #include "BKE_collection.h" | |||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_constraint.h" | #include "BKE_constraint.h" | ||||
| #include "BKE_fcurve.h" | #include "BKE_fcurve.h" | ||||
| #include "BKE_group.h" | |||||
| #include "BKE_layer.h" | #include "BKE_layer.h" | ||||
| #include "BKE_library.h" | #include "BKE_library.h" | ||||
| #include "BKE_library_override.h" | #include "BKE_library_override.h" | ||||
| #include "BKE_library_query.h" | #include "BKE_library_query.h" | ||||
| #include "BKE_library_remap.h" | #include "BKE_library_remap.h" | ||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "BKE_report.h" | #include "BKE_report.h" | ||||
| #include "BKE_scene.h" | #include "BKE_scene.h" | ||||
| Show All 34 Lines | static void set_operation_types(SpaceOops *soops, ListBase *lb, | ||||
| int *datalevel) | int *datalevel) | ||||
| { | { | ||||
| TreeElement *te; | TreeElement *te; | ||||
| TreeStoreElem *tselem; | TreeStoreElem *tselem; | ||||
| for (te = lb->first; te; te = te->next) { | for (te = lb->first; te; te = te->next) { | ||||
| tselem = TREESTORE(te); | tselem = TREESTORE(te); | ||||
| if (tselem->flag & TSE_SELECTED) { | if (tselem->flag & TSE_SELECTED) { | ||||
| if (tselem->type) { | if (ELEM(tselem->type, TSE_R_LAYER, TSE_SCENE_COLLECTION_BASE)) { | ||||
| /* Don't let immutable render layer item affect menu. */ | |||||
| } | |||||
| else if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { | |||||
| /* Layer collection points to collection ID. */ | |||||
| if (*datalevel == 0) | if (*datalevel == 0) | ||||
| *datalevel = tselem->type; | *datalevel = tselem->type; | ||||
| else if (*datalevel != tselem->type) | else if (*datalevel != tselem->type) | ||||
| *datalevel = -1; | *datalevel = -1; | ||||
| } | } | ||||
| else { | else { | ||||
| int idcode = GS(tselem->id->name); | int idcode = GS(tselem->id->name); | ||||
| switch (idcode) { | switch (idcode) { | ||||
| ▲ Show 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | if (a == te->index && mtex[a]) { | ||||
| if (mtex[a]->tex) { | if (mtex[a]->tex) { | ||||
| id_us_min(&mtex[a]->tex->id); | id_us_min(&mtex[a]->tex->id); | ||||
| mtex[a]->tex = NULL; | mtex[a]->tex = NULL; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void unlink_group_cb( | static void unlink_collection_cb( | ||||
| bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), | bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), | ||||
| TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) | TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) | ||||
| { | { | ||||
| Group *group = (Group *)tselem->id; | Main *bmain = CTX_data_main(C); | ||||
| Collection *collection = (Collection *)tselem->id; | |||||
| if (tsep) { | if (tsep) { | ||||
| if (GS(tsep->id->name) == ID_OB) { | if (GS(tsep->id->name) == ID_OB) { | ||||
| Object *ob = (Object *)tsep->id; | Object *ob = (Object *)tsep->id; | ||||
| ob->dup_group = NULL; | ob->dup_group = NULL; | ||||
| DEG_relations_tag_update(bmain); | |||||
| } | } | ||||
| else if (GS(tsep->id->name) == ID_GR) { | |||||
| Collection *parent = (Collection *)tsep->id; | |||||
| id_fake_user_set(&collection->id); | |||||
| BKE_collection_child_remove(bmain, parent, collection); | |||||
| DEG_relations_tag_update(bmain); | |||||
| } | } | ||||
| else { | else if (GS(tsep->id->name) == ID_SCE) { | ||||
| Collection *parent = BKE_collection_master((Scene *)tsep->id); | |||||
| id_fake_user_set(&collection->id); | |||||
| BKE_collection_child_remove(bmain, parent, collection); | |||||
| DEG_relations_tag_update(bmain); | |||||
| } | |||||
| } | |||||
| } | |||||
| static void unlink_object_cb( | |||||
| bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), | |||||
| TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) | |||||
| { | |||||
| Main *bmain = CTX_data_main(C); | Main *bmain = CTX_data_main(C); | ||||
| BKE_libblock_delete(bmain, group); | Object *ob = (Object *)tselem->id; | ||||
| if (tsep) { | |||||
| if (GS(tsep->id->name) == ID_GR) { | |||||
| Collection *parent = (Collection *)tsep->id; | |||||
| BKE_collection_object_remove(bmain, parent, ob, true); | |||||
| DEG_relations_tag_update(bmain); | |||||
| } | |||||
| else if (GS(tsep->id->name) == ID_SCE) { | |||||
| Collection *parent = BKE_collection_master((Scene *)tsep->id); | |||||
| BKE_collection_object_remove(bmain, parent, ob, true); | |||||
| DEG_relations_tag_update(bmain); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| static void unlink_world_cb( | static void unlink_world_cb( | ||||
| bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), | bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), | ||||
| TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) | TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) | ||||
| { | { | ||||
| Scene *parscene = (Scene *)tsep->id; | Scene *parscene = (Scene *)tsep->id; | ||||
| Show All 10 Lines | static void outliner_do_libdata_operation( | ||||
| void *user_data) | void *user_data) | ||||
| { | { | ||||
| TreeElement *te; | TreeElement *te; | ||||
| TreeStoreElem *tselem; | TreeStoreElem *tselem; | ||||
| for (te = lb->first; te; te = te->next) { | for (te = lb->first; te; te = te->next) { | ||||
| tselem = TREESTORE(te); | tselem = TREESTORE(te); | ||||
| if (tselem->flag & TSE_SELECTED) { | if (tselem->flag & TSE_SELECTED) { | ||||
| if (tselem->type == 0) { | if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { | ||||
| TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL; | TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL; | ||||
| operation_cb(C, reports, scene, te, tsep, tselem, user_data); | operation_cb(C, reports, scene, te, tsep, tselem, user_data); | ||||
| } | } | ||||
| } | } | ||||
| if (TSELEM_OPEN(tselem, soops)) { | if (TSELEM_OPEN(tselem, soops)) { | ||||
| outliner_do_libdata_operation(C, reports, scene, soops, &te->subtree, operation_cb, user_data); | outliner_do_libdata_operation(C, reports, scene, soops, &te->subtree, operation_cb, user_data); | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 248 Lines • ▼ Show 20 Lines | if (id) { | ||||
| RNA_id_pointer_create(&parscene->id, &ptr); | RNA_id_pointer_create(&parscene->id, &ptr); | ||||
| prop = RNA_struct_find_property(&ptr, "world"); | prop = RNA_struct_find_property(&ptr, "world"); | ||||
| id_single_user(C, id, &ptr, prop); | id_single_user(C, id, &ptr, prop); | ||||
| } | } | ||||
| } | } | ||||
| static void group_linkobs2scene_cb( | |||||
| bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), | |||||
| TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) | |||||
| { | |||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | |||||
| SceneCollection *sc = CTX_data_scene_collection(C); | |||||
| Group *group = (Group *)tselem->id; | |||||
| Base *base; | |||||
| FOREACH_GROUP_OBJECT_BEGIN(group, object) | |||||
| { | |||||
| base = BKE_view_layer_base_find(view_layer, object); | |||||
| if (!base) { | |||||
| /* link to scene */ | |||||
| BKE_collection_object_add(&scene->id, sc, object); | |||||
| base = BKE_view_layer_base_find(view_layer, object); | |||||
| id_us_plus(&object->id); | |||||
| } | |||||
| base->flag |= BASE_SELECTED; | |||||
| } | |||||
| FOREACH_GROUP_OBJECT_END; | |||||
| } | |||||
| static void group_instance_cb( | |||||
| bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), | |||||
| TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) | |||||
| { | |||||
| Group *group = (Group *)tselem->id; | |||||
| Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, scene->cursor.location, NULL, false, scene->layact); | |||||
| ob->dup_group = group; | |||||
| ob->transflag |= OB_DUPLIGROUP; | |||||
| id_lib_extern(&group->id); | |||||
| } | |||||
| /** | /** | ||||
| * \param select_recurse: Set to false for operations which are already recursively operating on their children. | * \param select_recurse: Set to false for operations which are already recursively operating on their children. | ||||
| */ | */ | ||||
| void outliner_do_object_operation_ex( | void outliner_do_object_operation_ex( | ||||
| bContext *C, ReportList *reports, Scene *scene_act, SpaceOops *soops, ListBase *lb, | bContext *C, ReportList *reports, Scene *scene_act, SpaceOops *soops, ListBase *lb, | ||||
| outliner_operation_cb operation_cb, bool select_recurse) | outliner_operation_cb operation_cb, bool select_recurse) | ||||
| { | { | ||||
| TreeElement *te; | TreeElement *te; | ||||
| ▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | |||||
| } eOutliner_PropConstraintOps; | } eOutliner_PropConstraintOps; | ||||
| typedef enum eOutliner_PropModifierOps { | typedef enum eOutliner_PropModifierOps { | ||||
| OL_MODIFIER_OP_TOGVIS = 1, | OL_MODIFIER_OP_TOGVIS = 1, | ||||
| OL_MODIFIER_OP_TOGREN, | OL_MODIFIER_OP_TOGREN, | ||||
| OL_MODIFIER_OP_DELETE | OL_MODIFIER_OP_DELETE | ||||
| } eOutliner_PropModifierOps; | } eOutliner_PropModifierOps; | ||||
| typedef enum eOutliner_PropCollectionOps { | |||||
| OL_COLLECTION_OP_OBJECTS_ADD = 1, | |||||
| OL_COLLECTION_OP_OBJECTS_REMOVE, | |||||
| OL_COLLECTION_OP_OBJECTS_SELECT, | |||||
| OL_COLLECTION_OP_COLLECTION_NEW, | |||||
| OL_COLLECTION_OP_COLLECTION_COPY, | |||||
| OL_COLLECTION_OP_COLLECTION_DEL, | |||||
| OL_COLLECTION_OP_COLLECTION_UNLINK, | |||||
| OL_COLLECTION_OP_GROUP_CREATE, | |||||
| } eOutliner_PropCollectionOps; | |||||
| static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg)) | static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg)) | ||||
| { | { | ||||
| bPoseChannel *pchan = (bPoseChannel *)te->directdata; | bPoseChannel *pchan = (bPoseChannel *)te->directdata; | ||||
| if (event == OL_DOP_SELECT) | if (event == OL_DOP_SELECT) | ||||
| pchan->bone->flag |= BONE_SELECTED; | pchan->bone->flag |= BONE_SELECTED; | ||||
| else if (event == OL_DOP_DESELECT) | else if (event == OL_DOP_DESELECT) | ||||
| pchan->bone->flag &= ~BONE_SELECTED; | pchan->bone->flag &= ~BONE_SELECTED; | ||||
| ▲ Show 20 Lines • Show All 134 Lines • ▼ Show 20 Lines | static void modifier_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *Carg) | ||||
| } | } | ||||
| else if (event == OL_MODIFIER_OP_DELETE) { | else if (event == OL_MODIFIER_OP_DELETE) { | ||||
| ED_object_modifier_remove(NULL, bmain, ob, md); | ED_object_modifier_remove(NULL, bmain, ob, md); | ||||
| WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER | NA_REMOVED, ob); | WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER | NA_REMOVED, ob); | ||||
| te->store_elem->flag &= ~TSE_SELECTED; | te->store_elem->flag &= ~TSE_SELECTED; | ||||
| } | } | ||||
| } | } | ||||
| static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *Carg) | |||||
| { | |||||
| bContext *C = (bContext *)Carg; | |||||
| Scene *scene = CTX_data_scene(C); | |||||
| LayerCollection *lc = te->directdata; | |||||
| ID *id = te->store_elem->id; | |||||
| SceneCollection *sc = lc->scene_collection; | |||||
| if (event == OL_COLLECTION_OP_OBJECTS_ADD) { | |||||
| CTX_DATA_BEGIN (C, Object *, ob, selected_objects) | |||||
| { | |||||
| BKE_collection_object_add(id, sc, ob); | |||||
| } | |||||
| CTX_DATA_END; | |||||
| WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); | |||||
| } | |||||
| else if (event == OL_COLLECTION_OP_OBJECTS_REMOVE) { | |||||
| Main *bmain = CTX_data_main(C); | |||||
| CTX_DATA_BEGIN (C, Object *, ob, selected_objects) | |||||
| { | |||||
| BKE_collection_object_remove(bmain, id, sc, ob, true); | |||||
| } | |||||
| CTX_DATA_END; | |||||
| WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); | |||||
| te->store_elem->flag &= ~TSE_SELECTED; | |||||
| } | |||||
| else if (event == OL_COLLECTION_OP_OBJECTS_SELECT) { | |||||
| BKE_layer_collection_objects_select(lc); | |||||
| WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene); | |||||
| } | |||||
| else if (event == OL_COLLECTION_OP_COLLECTION_NEW) { | |||||
| if (GS(id->name) == ID_GR) { | |||||
| BKE_collection_add(id, sc, COLLECTION_TYPE_GROUP_INTERNAL, NULL); | |||||
| } | |||||
| else { | |||||
| BLI_assert(GS(id->name) == ID_SCE); | |||||
| BKE_collection_add(id, sc, COLLECTION_TYPE_NONE, NULL); | |||||
| } | |||||
| WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); | |||||
| } | |||||
| else if (event == OL_COLLECTION_OP_COLLECTION_COPY) { | |||||
| BKE_layer_collection_duplicate(id, lc); | |||||
| DEG_relations_tag_update(CTX_data_main(C)); | |||||
| WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); | |||||
| } | |||||
| else if (event == OL_COLLECTION_OP_COLLECTION_UNLINK) { | |||||
| ViewLayer *view_layer = CTX_data_view_layer(C); | |||||
| if (BLI_findindex(&view_layer->layer_collections, lc) == -1) { | |||||
| /* we can't unlink if the layer collection wasn't directly linked */ | |||||
| TODO_LAYER_OPERATORS; /* this shouldn't be in the menu in those cases */ | |||||
| } | |||||
| else { | |||||
| BKE_collection_unlink(view_layer, lc); | |||||
| DEG_relations_tag_update(CTX_data_main(C)); | |||||
| WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); | |||||
| } | |||||
| } | |||||
| else if (event == OL_COLLECTION_OP_COLLECTION_DEL) { | |||||
| if (BKE_collection_remove(id, sc)) { | |||||
| DEG_relations_tag_update(CTX_data_main(C)); | |||||
| WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); | |||||
| } | |||||
| else { | |||||
| /* we can't remove the master collection */ | |||||
| TODO_LAYER_OPERATORS; /* this shouldn't be in the menu in those cases */ | |||||
| } | |||||
| } | |||||
| else if (event == OL_COLLECTION_OP_GROUP_CREATE) { | |||||
| Main *bmain = CTX_data_main(C); | |||||
| BKE_collection_group_create(bmain, scene, lc); | |||||
| DEG_relations_tag_update(bmain); | |||||
| /* TODO(sergey): Use proper flag for tagging here. */ | |||||
| DEG_id_tag_update(&scene->id, 0); | |||||
| WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); | |||||
| } | |||||
| else { | |||||
| BLI_assert(!"Collection operation not fully implemented!"); | |||||
| } | |||||
| } | |||||
| static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb, | static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb, | ||||
| void (*operation_cb)(int, TreeElement *, TreeStoreElem *, void *), | void (*operation_cb)(int, TreeElement *, TreeStoreElem *, void *), | ||||
| void *arg) | void *arg) | ||||
| { | { | ||||
| TreeElement *te; | TreeElement *te; | ||||
| TreeStoreElem *tselem; | TreeStoreElem *tselem; | ||||
| for (te = lb->first; te; te = te->next) { | for (te = lb->first; te; te = te->next) { | ||||
| ▲ Show 20 Lines • Show All 203 Lines • ▼ Show 20 Lines | void OUTLINER_OT_object_operation(wmOperatorType *ot) | ||||
| ot->flag = 0; | ot->flag = 0; | ||||
| ot->prop = RNA_def_enum(ot->srna, "type", prop_object_op_types, 0, "Object Operation", ""); | ot->prop = RNA_def_enum(ot->srna, "type", prop_object_op_types, 0, "Object Operation", ""); | ||||
| } | } | ||||
| /* **************************************** */ | /* **************************************** */ | ||||
| typedef enum eOutliner_PropGroupOps { | |||||
| OL_GROUPOP_UNLINK = 1, | |||||
| OL_GROUPOP_LOCAL, | |||||
| OL_GROUPOP_STATIC_OVERRIDE, | |||||
| OL_GROUPOP_LINK, | |||||
| OL_GROUPOP_DELETE, | |||||
| OL_GROUPOP_REMAP, | |||||
| OL_GROUPOP_INSTANCE, | |||||
| OL_GROUPOP_TOGVIS, | |||||
| OL_GROUPOP_TOGSEL, | |||||
| OL_GROUPOP_TOGREN, | |||||
| OL_GROUPOP_RENAME, | |||||
| } eOutliner_PropGroupOps; | |||||
| static const EnumPropertyItem prop_group_op_types[] = { | |||||
| {OL_GROUPOP_UNLINK, "UNLINK", 0, "Unlink Group", ""}, | |||||
| {OL_GROUPOP_LOCAL, "LOCAL", 0, "Make Local Group", ""}, | |||||
| {OL_GROUPOP_STATIC_OVERRIDE, "STATIC_OVERRIDE", | |||||
| 0, "Add Static Override", "Add a local static override of that group"}, | |||||
| {OL_GROUPOP_LINK, "LINK", 0, "Link Group Objects to Scene", ""}, | |||||
| {OL_GROUPOP_DELETE, "DELETE", 0, "Delete Group", ""}, | |||||
| {OL_GROUPOP_REMAP, "REMAP", 0, "Remap Users", | |||||
| "Make all users of selected data-blocks to use instead current (clicked) one"}, | |||||
| {OL_GROUPOP_INSTANCE, "INSTANCE", 0, "Instance Groups in Scene", ""}, | |||||
| {OL_GROUPOP_TOGVIS, "TOGVIS", 0, "Toggle Visible Group", ""}, | |||||
| {OL_GROUPOP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""}, | |||||
| {OL_GROUPOP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""}, | |||||
| {OL_GROUPOP_RENAME, "RENAME", 0, "Rename", ""}, | |||||
| {0, NULL, 0, NULL, NULL} | |||||
| }; | |||||
| static int outliner_group_operation_exec(bContext *C, wmOperator *op) | |||||
| { | |||||
| Scene *scene = CTX_data_scene(C); | |||||
| SpaceOops *soops = CTX_wm_space_outliner(C); | |||||
| int event; | |||||
| /* check for invalid states */ | |||||
| if (soops == NULL) | |||||
| return OPERATOR_CANCELLED; | |||||
| event = RNA_enum_get(op->ptr, "type"); | |||||
| switch (event) { | |||||
| case OL_GROUPOP_UNLINK: | |||||
| outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_group_cb, NULL); | |||||
| break; | |||||
| case OL_GROUPOP_LOCAL: | |||||
| outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL); | |||||
| break; | |||||
| case OL_GROUPOP_STATIC_OVERRIDE: | |||||
| outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_static_override_cb, NULL); | |||||
| break; | |||||
| case OL_GROUPOP_LINK: | |||||
| outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL); | |||||
| break; | |||||
| case OL_GROUPOP_INSTANCE: | |||||
| outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_instance_cb, NULL); | |||||
| /* works without this except if you try render right after, see: 22027 */ | |||||
| DEG_relations_tag_update(CTX_data_main(C)); | |||||
| break; | |||||
| case OL_GROUPOP_DELETE: | |||||
| outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL); | |||||
| break; | |||||
| case OL_GROUPOP_REMAP: | |||||
| outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL); | |||||
| break; | |||||
| case OL_GROUPOP_RENAME: | |||||
| outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL); | |||||
| break; | |||||
| default: | |||||
| BLI_assert(0); | |||||
| } | |||||
| ED_undo_push(C, prop_group_op_types[event - 1].name); | |||||
| WM_event_add_notifier(C, NC_GROUP, NULL); | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| void OUTLINER_OT_group_operation(wmOperatorType *ot) | |||||
| { | |||||
| /* identifiers */ | |||||
| ot->name = "Outliner Group Operation"; | |||||
| ot->idname = "OUTLINER_OT_group_operation"; | |||||
| ot->description = ""; | |||||
| /* callbacks */ | |||||
| ot->invoke = WM_menu_invoke; | |||||
| ot->exec = outliner_group_operation_exec; | |||||
| ot->poll = ED_operator_outliner_active; | |||||
| ot->flag = 0; | |||||
| ot->prop = RNA_def_enum(ot->srna, "type", prop_group_op_types, 0, "Group Operation", ""); | |||||
| } | |||||
| /* **************************************** */ | |||||
| typedef enum eOutlinerIdOpTypes { | typedef enum eOutlinerIdOpTypes { | ||||
| OUTLINER_IDOP_INVALID = 0, | OUTLINER_IDOP_INVALID = 0, | ||||
| OUTLINER_IDOP_UNLINK, | OUTLINER_IDOP_UNLINK, | ||||
| OUTLINER_IDOP_LOCAL, | OUTLINER_IDOP_LOCAL, | ||||
| OUTLINER_IDOP_STATIC_OVERRIDE, | OUTLINER_IDOP_STATIC_OVERRIDE, | ||||
| OUTLINER_IDOP_SINGLE, | OUTLINER_IDOP_SINGLE, | ||||
| OUTLINER_IDOP_DELETE, | OUTLINER_IDOP_DELETE, | ||||
| Show All 38 Lines | static int outliner_id_operation_exec(bContext *C, wmOperator *op) | ||||
| set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); | set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); | ||||
| event = RNA_enum_get(op->ptr, "type"); | event = RNA_enum_get(op->ptr, "type"); | ||||
| switch (event) { | switch (event) { | ||||
| case OUTLINER_IDOP_UNLINK: | case OUTLINER_IDOP_UNLINK: | ||||
| { | { | ||||
| /* unlink datablock from its parent */ | /* unlink datablock from its parent */ | ||||
| if (objectlevel) { | |||||
| outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_object_cb, NULL); | |||||
| WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL); | |||||
| ED_undo_push(C, "Unlink Object"); | |||||
| break; | |||||
| } | |||||
| switch (idlevel) { | switch (idlevel) { | ||||
| case ID_AC: | case ID_AC: | ||||
| outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_action_cb, NULL); | outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_action_cb, NULL); | ||||
| WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); | WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); | ||||
| ED_undo_push(C, "Unlink action"); | ED_undo_push(C, "Unlink action"); | ||||
| break; | break; | ||||
| case ID_MA: | case ID_MA: | ||||
| Show All 9 Lines | case OUTLINER_IDOP_UNLINK: | ||||
| ED_undo_push(C, "Unlink texture"); | ED_undo_push(C, "Unlink texture"); | ||||
| break; | break; | ||||
| case ID_WO: | case ID_WO: | ||||
| outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_world_cb, NULL); | outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_world_cb, NULL); | ||||
| WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL); | WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL); | ||||
| ED_undo_push(C, "Unlink world"); | ED_undo_push(C, "Unlink world"); | ||||
| break; | break; | ||||
| case ID_GR: | |||||
| outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_collection_cb, NULL); | |||||
| WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL); | |||||
| ED_undo_push(C, "Unlink Collection"); | |||||
| break; | |||||
| default: | default: | ||||
| BKE_report(op->reports, RPT_WARNING, "Not yet implemented"); | BKE_report(op->reports, RPT_WARNING, "Not yet implemented"); | ||||
| break; | break; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case OUTLINER_IDOP_LOCAL: | case OUTLINER_IDOP_LOCAL: | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 521 Lines • ▼ Show 20 Lines | void OUTLINER_OT_modifier_operation(wmOperatorType *ot) | ||||
| ot->flag = 0; | ot->flag = 0; | ||||
| ot->prop = RNA_def_enum(ot->srna, "type", prop_modifier_op_types, 0, "Modifier Operation", ""); | ot->prop = RNA_def_enum(ot->srna, "type", prop_modifier_op_types, 0, "Modifier Operation", ""); | ||||
| } | } | ||||
| /* ******************** */ | /* ******************** */ | ||||
| static EnumPropertyItem prop_collection_op_types[] = { | |||||
| {OL_COLLECTION_OP_OBJECTS_ADD, "OBJECTS_ADD", ICON_ZOOMIN, "Add Selected", "Add selected objects to collection"}, | |||||
| {OL_COLLECTION_OP_OBJECTS_REMOVE, "OBJECTS_REMOVE", ICON_X, "Remove Selected", "Remove selected objects from collection"}, | |||||
| {OL_COLLECTION_OP_OBJECTS_SELECT, "OBJECTS_SELECT", ICON_RESTRICT_SELECT_OFF, "Select Objects", "Select collection objects"}, | |||||
| {OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"}, | |||||
| {OL_COLLECTION_OP_COLLECTION_COPY, "COLLECTION_DUPLI", ICON_NONE, "Duplicate Collection", "Duplicate the collection"}, | |||||
| {OL_COLLECTION_OP_COLLECTION_UNLINK, "COLLECTION_UNLINK", ICON_UNLINKED, "Unlink", "Unlink collection"}, | |||||
| {OL_COLLECTION_OP_COLLECTION_DEL, "COLLECTION_DEL", ICON_X, "Delete Collection", "Delete the collection"}, | |||||
| {OL_COLLECTION_OP_GROUP_CREATE, "GROUP_CREATE", ICON_GROUP, "Create Group", "Turn the collection into a group collection"}, | |||||
| {0, NULL, 0, NULL, NULL} | |||||
| }; | |||||
| static int outliner_collection_operation_exec(bContext *C, wmOperator *op) | |||||
| { | |||||
| SpaceOops *soops = CTX_wm_space_outliner(C); | |||||
| int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; | |||||
| eOutliner_PropCollectionOps event; | |||||
| event = RNA_enum_get(op->ptr, "type"); | |||||
| set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); | |||||
| outliner_do_data_operation(soops, datalevel, event, &soops->tree, collection_cb, C); | |||||
| outliner_cleanup_tree(soops); | |||||
| ED_undo_push(C, "Collection operation"); | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| static int outliner_collection_operation_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) | |||||
| { | |||||
| SpaceOops *soops = CTX_wm_space_outliner(C); | |||||
| wmOperatorType *ot = op->type; | |||||
| EnumPropertyItem *prop = &prop_collection_op_types[0]; | |||||
| uiPopupMenu *pup = UI_popup_menu_begin(C, "Collection", ICON_NONE); | |||||
| uiLayout *layout = UI_popup_menu_layout(pup); | |||||
| for (int i = 0; i < (ARRAY_SIZE(prop_collection_op_types) - 1); i++, prop++) { | |||||
| if (soops->outlinevis != SO_GROUPS || | |||||
| !ELEM(prop->value, | |||||
| OL_COLLECTION_OP_OBJECTS_SELECT, | |||||
| OL_COLLECTION_OP_COLLECTION_UNLINK, | |||||
| OL_COLLECTION_OP_GROUP_CREATE)) | |||||
| { | |||||
| uiItemEnumO_ptr(layout, ot, NULL, prop->icon, "type", prop->value); | |||||
| } | |||||
| } | |||||
| UI_popup_menu_end(C, pup); | |||||
| return OPERATOR_INTERFACE; | |||||
| } | |||||
| void OUTLINER_OT_collection_operation(wmOperatorType *ot) | |||||
| { | |||||
| PropertyRNA *prop; | |||||
| /* identifiers */ | |||||
| ot->name = "Outliner Collection Operation"; | |||||
| ot->idname = "OUTLINER_OT_collection_operation"; | |||||
| ot->description = ""; | |||||
| /* callbacks */ | |||||
| ot->invoke = outliner_collection_operation_invoke; | |||||
| ot->exec = outliner_collection_operation_exec; | |||||
| ot->poll = ED_operator_outliner_active; | |||||
| ot->flag = 0; | |||||
| prop = RNA_def_enum(ot->srna, "type", prop_collection_op_types, OL_COLLECTION_OP_OBJECTS_ADD, "Collection Operation", ""); | |||||
| RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); | |||||
| ot->prop = prop; | |||||
| } | |||||
| /* ******************** */ | |||||
| // XXX: select linked is for RNA structs only | // XXX: select linked is for RNA structs only | ||||
| static const EnumPropertyItem prop_data_op_types[] = { | static const EnumPropertyItem prop_data_op_types[] = { | ||||
| {OL_DOP_SELECT, "SELECT", 0, "Select", ""}, | {OL_DOP_SELECT, "SELECT", 0, "Select", ""}, | ||||
| {OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""}, | {OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""}, | ||||
| {OL_DOP_HIDE, "HIDE", 0, "Hide", ""}, | {OL_DOP_HIDE, "HIDE", 0, "Hide", ""}, | ||||
| {OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""}, | {OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""}, | ||||
| {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""}, | {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""}, | ||||
| {0, NULL, 0, NULL, NULL} | {0, NULL, 0, NULL, NULL} | ||||
| ▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | if (!(tselem->flag & TSE_SELECTED)) { | ||||
| tselem->flag |= TSE_SELECTED; | tselem->flag |= TSE_SELECTED; | ||||
| /* Only redraw, don't rebuild here because TreeElement pointers will | /* Only redraw, don't rebuild here because TreeElement pointers will | ||||
| * become invalid and operations will crash. */ | * become invalid and operations will crash. */ | ||||
| ED_region_tag_redraw_no_rebuild(ar); | ED_region_tag_redraw_no_rebuild(ar); | ||||
| } | } | ||||
| set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); | set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); | ||||
| if (scenelevel) { | if (scenelevel) { | ||||
| if (objectlevel || datalevel || idlevel) { | if (objectlevel || datalevel || idlevel) { | ||||
| BKE_report(reports, RPT_WARNING, "Mixed selection"); | BKE_report(reports, RPT_WARNING, "Mixed selection"); | ||||
| } | } | ||||
| else { | else { | ||||
| WM_operator_name_call(C, "OUTLINER_OT_scene_operation", WM_OP_INVOKE_REGION_WIN, NULL); | WM_operator_name_call(C, "OUTLINER_OT_scene_operation", WM_OP_INVOKE_REGION_WIN, NULL); | ||||
| } | } | ||||
| } | } | ||||
| else if (objectlevel) { | else if (objectlevel) { | ||||
| WM_menu_name_call(C, "OUTLINER_MT_context_object", WM_OP_INVOKE_REGION_WIN); | WM_menu_name_call(C, "OUTLINER_MT_object", WM_OP_INVOKE_REGION_WIN); | ||||
| } | } | ||||
| else if (idlevel) { | else if (idlevel) { | ||||
| if (idlevel == -1 || datalevel) { | if (idlevel == -1 || datalevel) { | ||||
| BKE_report(reports, RPT_WARNING, "Mixed selection"); | BKE_report(reports, RPT_WARNING, "Mixed selection"); | ||||
| } | } | ||||
| else { | else { | ||||
| switch (idlevel) { | switch (idlevel) { | ||||
| case ID_GR: | case ID_GR: | ||||
| WM_operator_name_call(C, "OUTLINER_OT_group_operation", WM_OP_INVOKE_REGION_WIN, NULL); | WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN); | ||||
| break; | break; | ||||
| case ID_LI: | case ID_LI: | ||||
| WM_operator_name_call(C, "OUTLINER_OT_lib_operation", WM_OP_INVOKE_REGION_WIN, NULL); | WM_operator_name_call(C, "OUTLINER_OT_lib_operation", WM_OP_INVOKE_REGION_WIN, NULL); | ||||
| break; | break; | ||||
| default: | default: | ||||
| WM_operator_name_call(C, "OUTLINER_OT_id_operation", WM_OP_INVOKE_REGION_WIN, NULL); | WM_operator_name_call(C, "OUTLINER_OT_id_operation", WM_OP_INVOKE_REGION_WIN, NULL); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else if (datalevel) { | else if (datalevel) { | ||||
| if (datalevel == -1) { | if (datalevel == -1) { | ||||
| BKE_report(reports, RPT_WARNING, "Mixed selection"); | BKE_report(reports, RPT_WARNING, "Mixed selection"); | ||||
| } | } | ||||
| else { | else { | ||||
| if (datalevel == TSE_ANIM_DATA) | if (datalevel == TSE_ANIM_DATA) | ||||
| WM_operator_name_call(C, "OUTLINER_OT_animdata_operation", WM_OP_INVOKE_REGION_WIN, NULL); | WM_operator_name_call(C, "OUTLINER_OT_animdata_operation", WM_OP_INVOKE_REGION_WIN, NULL); | ||||
| else if (datalevel == TSE_DRIVER_BASE) { | else if (datalevel == TSE_DRIVER_BASE) { | ||||
| /* do nothing... no special ops needed yet */ | /* do nothing... no special ops needed yet */ | ||||
| } | } | ||||
| else if (ELEM(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER)) { | else if (datalevel == TSE_LAYER_COLLECTION) { | ||||
| /*WM_operator_name_call(C, "OUTLINER_OT_renderdata_operation", WM_OP_INVOKE_REGION_WIN, NULL)*/ | WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN); | ||||
| } | } | ||||
| else if (datalevel == TSE_ID_BASE) { | else if (datalevel == TSE_ID_BASE) { | ||||
| /* do nothing... there are no ops needed here yet */ | /* do nothing... there are no ops needed here yet */ | ||||
| } | } | ||||
| else if (datalevel == TSE_CONSTRAINT) { | else if (datalevel == TSE_CONSTRAINT) { | ||||
| WM_operator_name_call(C, "OUTLINER_OT_constraint_operation", WM_OP_INVOKE_REGION_WIN, NULL); | WM_operator_name_call(C, "OUTLINER_OT_constraint_operation", WM_OP_INVOKE_REGION_WIN, NULL); | ||||
| } | } | ||||
| else if (datalevel == TSE_MODIFIER) { | else if (datalevel == TSE_MODIFIER) { | ||||
| WM_operator_name_call(C, "OUTLINER_OT_modifier_operation", WM_OP_INVOKE_REGION_WIN, NULL); | WM_operator_name_call(C, "OUTLINER_OT_modifier_operation", WM_OP_INVOKE_REGION_WIN, NULL); | ||||
| } | } | ||||
| else if (datalevel == TSE_LAYER_COLLECTION) { | else if (ELEM(soops->outlinevis, SO_COLLECTIONS, SO_VIEW_LAYER)) { | ||||
| WM_operator_name_call(C, "OUTLINER_OT_collection_operation", WM_OP_INVOKE_REGION_WIN, NULL); | WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN); | ||||
| } | |||||
| else if (datalevel == TSE_SCENE_COLLECTION) { | |||||
| WM_menu_name_call(C, "OUTLINER_MT_context_scene_collection", WM_OP_INVOKE_REGION_WIN); | |||||
| } | } | ||||
| else { | else { | ||||
| WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL); | WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return 1; | return 1; | ||||
| Show All 9 Lines | |||||
| static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) | static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) | ||||
| { | { | ||||
| ARegion *ar = CTX_wm_region(C); | ARegion *ar = CTX_wm_region(C); | ||||
| SpaceOops *soops = CTX_wm_space_outliner(C); | SpaceOops *soops = CTX_wm_space_outliner(C); | ||||
| uiBut *but = UI_context_active_but_get(C); | uiBut *but = UI_context_active_but_get(C); | ||||
| TreeElement *te; | TreeElement *te; | ||||
| float fmval[2]; | float fmval[2]; | ||||
| bool found = false; | |||||
| if (but) { | if (but) { | ||||
| UI_but_tooltip_timer_remove(C, but); | UI_but_tooltip_timer_remove(C, but); | ||||
| } | } | ||||
| UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); | UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); | ||||
| for (te = soops->tree.first; te; te = te->next) { | for (te = soops->tree.first; te; te = te->next) { | ||||
| if (do_outliner_operation_event(C, ar, soops, te, fmval)) { | if (do_outliner_operation_event(C, ar, soops, te, fmval)) { | ||||
| found = true; | |||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (!found) { | |||||
| /* Menus for clicking in empty space. */ | |||||
| if (ELEM(soops->outlinevis, SO_COLLECTIONS, SO_VIEW_LAYER)) { | |||||
| WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN); | |||||
| } | |||||
| } | |||||
| return OPERATOR_FINISHED; | return OPERATOR_FINISHED; | ||||
| } | } | ||||
| /* Menu only! Calls other operators */ | /* Menu only! Calls other operators */ | ||||
| void OUTLINER_OT_operation(wmOperatorType *ot) | void OUTLINER_OT_operation(wmOperatorType *ot) | ||||
| { | { | ||||
| ot->name = "Execute Operation"; | ot->name = "Execute Operation"; | ||||
| ot->idname = "OUTLINER_OT_operation"; | ot->idname = "OUTLINER_OT_operation"; | ||||
| ot->description = "Context menu for item operations"; | ot->description = "Context menu for item operations"; | ||||
| ot->invoke = outliner_operation; | ot->invoke = outliner_operation; | ||||
| ot->poll = ED_operator_outliner_active; | ot->poll = ED_operator_outliner_active; | ||||
| } | } | ||||
| /* ****************************************************** */ | /* ****************************************************** */ | ||||