diff options
Diffstat (limited to 'source/blender/editors/space_outliner/outliner_tools.c')
-rw-r--r-- | source/blender/editors/space_outliner/outliner_tools.c | 346 |
1 files changed, 268 insertions, 78 deletions
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index cf9deeaedf8..c30b14d43fa 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -53,10 +53,11 @@ #include "BKE_animsys.h" #include "BKE_context.h" #include "BKE_constraint.h" -#include "BKE_depsgraph.h" #include "BKE_fcurve.h" #include "BKE_group.h" +#include "BKE_layer.h" #include "BKE_library.h" +#include "BKE_library_override.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" #include "BKE_main.h" @@ -64,8 +65,12 @@ #include "BKE_scene.h" #include "BKE_sequencer.h" +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" + #include "ED_armature.h" #include "ED_object.h" +#include "ED_scene.h" #include "ED_screen.h" #include "ED_sequencer.h" #include "ED_util.h" @@ -308,7 +313,7 @@ static bool scene_cb(bContext *C, eOutliner_PropSceneOps event, TreeElement *UNU Scene *scene = (Scene *)tselem->id; if (event == OL_SCENE_OP_DELETE) { - if (ED_screen_delete_scene(C, scene)) { + if (ED_scene_delete(C, CTX_data_main(C), CTX_wm_window(C), scene)) { WM_event_add_notifier(C, NC_SCENE | NA_REMOVED, scene); } else { @@ -359,15 +364,15 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot) /* ******************************************** */ static void object_select_cb( - bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te, + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { - Base *base = (Base *)te->directdata; - - if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id); - if (base && ((base->object->restrictflag & OB_RESTRICT_VIEW) == 0)) { - base->flag |= SELECT; - base->object->flag |= SELECT; + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = (Object *)tselem->id; + Base *base = BKE_view_layer_base_find(view_layer, ob); + + if (base && ((base->flag & BASE_VISIBLED) != 0)) { + base->flag |= BASE_SELECTED; } } @@ -381,15 +386,15 @@ static void object_select_hierarchy_cb( } static void object_deselect_cb( - bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te, + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { - Base *base = (Base *)te->directdata; - - if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = (Object *)tselem->id; + Base *base = BKE_view_layer_base_find(view_layer, ob); + if (base) { - base->flag &= ~SELECT; - base->object->flag &= ~SELECT; + base->flag &= ~BASE_SELECTED; } } @@ -397,30 +402,27 @@ static void object_delete_cb( bContext *C, ReportList *reports, Scene *scene, TreeElement *te, TreeStoreElem *tsep, TreeStoreElem *tselem, void *user_data) { - Base *base = (Base *)te->directdata; - - if (base == NULL) - base = BKE_scene_base_find(scene, (Object *)tselem->id); - if (base) { + Object *ob = (Object *)tselem->id; + if (ob) { Main *bmain = CTX_data_main(C); - if (base->object->id.tag & LIB_TAG_INDIRECT) { - BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2); + if (ob->id.tag & LIB_TAG_INDIRECT) { + BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", ob->id.name + 2); return; } - else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && - ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) + else if (BKE_library_ID_is_indirectly_used(bmain, ob) && + ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0) { BKE_reportf(reports, RPT_WARNING, "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", - base->object->id.name + 2, scene->id.name + 2); + ob->id.name + 2, scene->id.name + 2); return; } // check also library later - if (scene->obedit == base->object) + if (ob == CTX_data_edit_object(C)) { ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); - - ED_base_object_free_and_unlink(CTX_data_main(C), scene, base); + } + ED_object_base_free_and_unlink(CTX_data_main(C), scene, ob); /* leave for ED_outliner_id_unref to handle */ #if 0 te->directdata = NULL; @@ -453,6 +455,19 @@ static void id_local_cb( } } +static void id_static_override_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +{ + if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) { + Main *bmain = CTX_data_main(C); + ID *override_id = BKE_override_static_create_from_id(bmain, tselem->id); + if (override_id != NULL) { + BKE_main_id_clear_newpoins(bmain); + } + } +} + static void id_fake_user_set_cb( bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) @@ -518,23 +533,27 @@ static void singleuser_world_cb( } static void group_linkobs2scene_cb( - bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), + 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; - GroupObject *gob; Base *base; - for (gob = group->gobject.first; gob; gob = gob->next) { - base = BKE_scene_base_find(scene, gob->ob); + FOREACH_GROUP_OBJECT_BEGIN(group, object) + { + base = BKE_view_layer_base_find(view_layer, object); if (!base) { /* link to scene */ - base = BKE_scene_base_add(scene, gob->ob); - id_us_plus(&gob->ob->id); + BKE_collection_object_add(&scene->id, sc, object); + base = BKE_view_layer_base_find(view_layer, object); + id_us_plus(&object->id); } - base->object->flag |= SELECT; - base->flag |= SELECT; + + base->flag |= BASE_SELECTED; } + FOREACH_GROUP_OBJECT_END; } static void group_instance_cb( @@ -566,7 +585,7 @@ void outliner_do_object_operation_ex( // when objects selected in other scenes... dunno if that should be allowed Scene *scene_owner = (Scene *)outliner_search_back(soops, te, ID_SCE); if (scene_owner && scene_act != scene_owner) { - ED_screen_set_scene(C, CTX_wm_screen(C), scene_owner); + WM_window_change_active_scene(CTX_data_main(C), C, CTX_wm_window(C), scene_owner); } /* important to use 'scene_owner' not scene_act else deleting objects can crash. * only use 'scene_act' when 'scene_owner' is NULL, which can happen when the @@ -653,6 +672,17 @@ typedef enum eOutliner_PropModifierOps { OL_MODIFIER_OP_DELETE } 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)) { bPoseChannel *pchan = (bPoseChannel *)te->directdata; @@ -788,12 +818,12 @@ static void modifier_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem if (event == OL_MODIFIER_OP_TOGVIS) { md->mode ^= eModifierMode_Realtime; - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); } else if (event == OL_MODIFIER_OP_TOGREN) { md->mode ^= eModifierMode_Render; - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); + DEG_id_tag_update(&ob->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); } else if (event == OL_MODIFIER_OP_DELETE) { @@ -803,6 +833,90 @@ static void modifier_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem } } +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, void (*operation_cb)(int, TreeElement *, TreeStoreElem *, void *), void *arg) @@ -827,12 +941,13 @@ static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *s { Base *child_base, *base_next; Object *parent; + ViewLayer *view_layer = CTX_data_view_layer(C); if (!base) { return NULL; } - for (child_base = scene->base.first; child_base; child_base = base_next) { + for (child_base = view_layer->object_bases.first; child_base; child_base = base_next) { base_next = child_base->next; for (parent = child_base->object->parent; parent && (parent != base->object); parent = parent->parent); if (parent) { @@ -855,7 +970,7 @@ static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *s base->object->id.name + 2, scene->id.name + 2); return base_next; } - ED_base_object_free_and_unlink(CTX_data_main(C), scene, base); + ED_object_base_free_and_unlink(CTX_data_main(C), scene, base->object); return base_next; } @@ -863,11 +978,12 @@ static void object_delete_hierarchy_cb( bContext *C, ReportList *reports, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { + ViewLayer *view_layer = CTX_data_view_layer(C); Base *base = (Base *)te->directdata; - Object *obedit = scene->obedit; + Object *obedit = CTX_data_edit_object(C); if (!base) { - base = BKE_scene_base_find(scene, (Object *)tselem->id); + base = BKE_view_layer_base_find(view_layer, (Object *)tselem->id); } if (base) { /* Check also library later. */ @@ -911,9 +1027,6 @@ static const EnumPropertyItem prop_object_op_types[] = { {OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""}, {OL_OP_REMAP, "REMAP", 0, "Remap Users", "Make all users of selected data-blocks to use instead a new chosen one"}, - {OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""}, - {OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""}, - {OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""}, {OL_OP_RENAME, "RENAME", 0, "Rename", ""}, {0, NULL, 0, NULL, NULL} }; @@ -922,6 +1035,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); + wmWindow *win = CTX_wm_window(C); SpaceOops *soops = CTX_wm_space_outliner(C); int event; const char *str = NULL; @@ -936,7 +1050,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) Scene *sce = scene; // to be able to delete, scenes are set... outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_select_cb); if (scene != sce) { - ED_screen_set_scene(C, CTX_wm_screen(C), sce); + WM_window_change_active_scene(bmain, C, win, sce); } str = "Select Objects"; @@ -946,8 +1060,8 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) Scene *sce = scene; // to be able to delete, scenes are set... outliner_do_object_operation_ex(C, op->reports, scene, soops, &soops->tree, object_select_hierarchy_cb, false); if (scene != sce) { - ED_screen_set_scene(C, CTX_wm_screen(C), sce); - } + WM_window_change_active_scene(bmain, C, win, sce); + } str = "Select Object Hierarchy"; WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } @@ -966,7 +1080,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) * cleanup tree here to prevent such cases. */ outliner_cleanup_tree(soops); - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); str = "Delete Objects"; WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); } @@ -976,7 +1090,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) /* XXX: See OL_OP_DELETE comment above. */ outliner_cleanup_tree(soops); - DAG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); str = "Delete Object Hierarchy"; WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); } @@ -988,21 +1102,6 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb); str = "Localized Objects"; } - else if (event == OL_OP_TOGVIS) { - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_visibility_cb); - str = "Toggle Visibility"; - WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene); - } - else if (event == OL_OP_TOGSEL) { - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_selectability_cb); - str = "Toggle Selectability"; - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } - else if (event == OL_OP_TOGREN) { - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_renderability_cb); - str = "Toggle Renderability"; - WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene); - } else if (event == OL_OP_RENAME) { outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb); str = "Rename Object"; @@ -1040,6 +1139,7 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot) typedef enum eOutliner_PropGroupOps { OL_GROUPOP_UNLINK = 1, OL_GROUPOP_LOCAL, + OL_GROUPOP_STATIC_OVERRIDE, OL_GROUPOP_LINK, OL_GROUPOP_DELETE, OL_GROUPOP_REMAP, @@ -1053,6 +1153,8 @@ typedef enum 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", @@ -1084,13 +1186,16 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op) 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 */ - DAG_relations_tag_update(CTX_data_main(C)); + 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); @@ -1098,15 +1203,6 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op) case OL_GROUPOP_REMAP: outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL); break; - case OL_GROUPOP_TOGVIS: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_visibility_cb, NULL); - break; - case OL_GROUPOP_TOGSEL: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_selectability_cb, NULL); - break; - case OL_GROUPOP_TOGREN: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_renderability_cb, NULL); - break; case OL_GROUPOP_RENAME: outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL); break; @@ -1145,6 +1241,7 @@ typedef enum eOutlinerIdOpTypes { OUTLINER_IDOP_UNLINK, OUTLINER_IDOP_LOCAL, + OUTLINER_IDOP_STATIC_OVERRIDE, OUTLINER_IDOP_SINGLE, OUTLINER_IDOP_DELETE, OUTLINER_IDOP_REMAP, @@ -1160,6 +1257,8 @@ typedef enum eOutlinerIdOpTypes { static const EnumPropertyItem prop_id_op_types[] = { {OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""}, {OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""}, + {OUTLINER_IDOP_STATIC_OVERRIDE, "STATIC_OVERRIDE", + 0, "Add Static Override", "Add a local static override of this data-block"}, {OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""}, {OUTLINER_IDOP_DELETE, "DELETE", 0, "Delete", "WARNING: no undo"}, {OUTLINER_IDOP_REMAP, "REMAP", 0, "Remap Users", @@ -1229,6 +1328,13 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) ED_undo_push(C, "Localized Data"); break; } + case OUTLINER_IDOP_STATIC_OVERRIDE: + { + /* make local */ + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_static_override_cb, NULL); + ED_undo_push(C, "Overrided Data"); + break; + } case OUTLINER_IDOP_SINGLE: { /* make single user */ @@ -1628,7 +1734,7 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op) /* update dependencies */ if (updateDeps) { /* rebuild depsgraph for the new deps */ - DAG_relations_tag_update(CTX_data_main(C)); + DEG_relations_tag_update(CTX_data_main(C)); } return OPERATOR_FINISHED; @@ -1746,6 +1852,84 @@ void OUTLINER_OT_modifier_operation(wmOperatorType *ot) /* ******************** */ +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", "Selected 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 static const EnumPropertyItem prop_data_op_types[] = { {OL_DOP_SELECT, "SELECT", 0, "Select", ""}, @@ -1878,7 +2062,7 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop } } else if (objectlevel) { - WM_operator_name_call(C, "OUTLINER_OT_object_operation", WM_OP_INVOKE_REGION_WIN, NULL); + WM_menu_name_call(C, "OUTLINER_MT_context_object", WM_OP_INVOKE_REGION_WIN); } else if (idlevel) { if (idlevel == -1 || datalevel) { @@ -1920,6 +2104,12 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop else if (datalevel == TSE_MODIFIER) { WM_operator_name_call(C, "OUTLINER_OT_modifier_operation", WM_OP_INVOKE_REGION_WIN, NULL); } + else if (datalevel == TSE_LAYER_COLLECTION) { + WM_operator_name_call(C, "OUTLINER_OT_collection_operation", WM_OP_INVOKE_REGION_WIN, NULL); + } + else if (datalevel == TSE_SCENE_COLLECTION) { + WM_menu_name_call(C, "OUTLINER_MT_context_scene_collection", WM_OP_INVOKE_REGION_WIN); + } else { WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL); } |