diff options
Diffstat (limited to 'source/blender/editors/space_outliner/outliner_tools.c')
-rw-r--r-- | source/blender/editors/space_outliner/outliner_tools.c | 453 |
1 files changed, 217 insertions, 236 deletions
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 2707e130598..2f84340e34e 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -33,8 +33,8 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" +#include "DNA_collection_types.h" #include "DNA_gpencil_types.h" -#include "DNA_group_types.h" #include "DNA_lamp_types.h" #include "DNA_linestyle_types.h" #include "DNA_material_types.h" @@ -51,21 +51,27 @@ #include "BLI_utildefines.h" #include "BKE_animsys.h" +#include "BKE_collection.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" #include "BKE_report.h" #include "BKE_scene.h" +#include "BKE_screen.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_undo.h" @@ -100,7 +106,8 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb, for (te = lb->first; te; te = te->next) { tselem = TREESTORE(te); if (tselem->flag & TSE_SELECTED) { - if (tselem->type) { + /* Layer collection points to collection ID. */ + if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { if (*datalevel == 0) *datalevel = tselem->type; else if (*datalevel != tselem->type) @@ -124,6 +131,9 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb, case ID_LI: if (*idlevel == 0) *idlevel = idcode; else if (*idlevel != idcode) *idlevel = -1; + if (ELEM(*datalevel, TSE_VIEW_COLLECTION_BASE, TSE_SCENE_COLLECTION_BASE)) { + *datalevel = 0; + } break; } } @@ -191,19 +201,7 @@ static void unlink_texture_cb( MTex **mtex = NULL; int a; - if (GS(tsep->id->name) == ID_MA) { - Material *ma = (Material *)tsep->id; - mtex = ma->mtex; - } - else if (GS(tsep->id->name) == ID_LA) { - Lamp *la = (Lamp *)tsep->id; - mtex = la->mtex; - } - else if (GS(tsep->id->name) == ID_WO) { - World *wrld = (World *)tsep->id; - mtex = wrld->mtex; - } - else if (GS(tsep->id->name) == ID_LS) { + if (GS(tsep->id->name) == ID_LS) { FreestyleLineStyle *ls = (FreestyleLineStyle *)tsep->id; mtex = ls->mtex; } @@ -221,21 +219,59 @@ static void unlink_texture_cb( } } -static void unlink_group_cb( +static void unlink_collection_cb( bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), 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 (GS(tsep->id->name) == ID_OB) { Object *ob = (Object *)tsep->id; ob->dup_group = NULL; + DEG_id_tag_update(&ob->id, OB_RECALC_OB); + 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_id_tag_update(&parent->id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + } + else if (GS(tsep->id->name) == ID_SCE) { + Scene *scene = (Scene *)tsep->id; + Collection *parent = BKE_collection_master(scene); + id_fake_user_set(&collection->id); + BKE_collection_child_remove(bmain, parent, collection); + DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); } } - else { - Main *bmain = CTX_data_main(C); - BKE_libblock_delete(bmain, group); +} + +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); + 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_id_tag_update(&parent->id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + } + else if (GS(tsep->id->name) == ID_SCE) { + Scene *scene = (Scene *)tsep->id; + Collection *parent = BKE_collection_master(scene); + BKE_collection_object_remove(bmain, parent, ob, true); + DEG_id_tag_update(&scene->id, DEG_TAG_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + } } } @@ -262,7 +298,7 @@ static void outliner_do_libdata_operation( for (te = lb->first; te; te = te->next) { tselem = TREESTORE(te); 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; operation_cb(C, reports, scene, te, tsep, tselem, user_data); } @@ -308,7 +344,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 +395,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; + 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 == 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; + if (base && ((base->flag & BASE_VISIBLE) != 0)) { + base->flag |= BASE_SELECTED; } } @@ -381,15 +417,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; + 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 == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id); if (base) { - base->flag &= ~SELECT; - base->object->flag &= ~SELECT; + base->flag &= ~BASE_SELECTED; } } @@ -397,31 +433,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_WAITCURSOR); } - - 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; @@ -454,6 +486,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,38 +563,6 @@ static void singleuser_world_cb( } } -static void group_linkobs2scene_cb( - bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - 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); - if (!base) { - /* link to scene */ - base = BKE_scene_base_add(scene, gob->ob); - id_us_plus(&gob->ob->id); - } - base->object->flag |= SELECT; - base->flag |= SELECT; - } -} - -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, 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. */ @@ -567,7 +580,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_set_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 @@ -790,12 +803,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) { @@ -829,12 +842,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) { @@ -857,7 +871,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; } @@ -865,11 +879,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. */ @@ -886,6 +901,7 @@ static void object_delete_hierarchy_cb( #endif } + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); } @@ -903,6 +919,8 @@ enum { OL_OP_TOGSEL, OL_OP_TOGREN, OL_OP_RENAME, + OL_OP_OBJECT_MODE_ENTER, + OL_OP_OBJECT_MODE_EXIT, }; static const EnumPropertyItem prop_object_op_types[] = { @@ -913,10 +931,9 @@ 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", ""}, + {OL_OP_OBJECT_MODE_ENTER, "OBJECT_MODE_ENTER", 0, "Enter Mode", ""}, + {OL_OP_OBJECT_MODE_EXIT, "OBJECT_MODE_EXIT", 0, "Exit Mode", ""}, {0, NULL, 0, NULL, NULL} }; @@ -924,6 +941,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; @@ -938,24 +956,27 @@ 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_set_active_scene(bmain, C, win, sce); } str = "Select Objects"; + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } else if (event == OL_OP_SELECT_HIERARCHY) { 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_set_active_scene(bmain, C, win, sce); } str = "Select Object Hierarchy"; + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } else if (event == OL_OP_DESELECT) { outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_deselect_cb); str = "Deselect Objects"; + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } else if (event == OL_OP_DELETE) { @@ -968,8 +989,9 @@ 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"; + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); } else if (event == OL_OP_DELETE_HIERARCHY) { @@ -978,8 +1000,9 @@ 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"; + DEG_id_tag_update(&scene->id, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); } else if (event == OL_OP_REMAP) { @@ -990,25 +1013,18 @@ 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"; } + else if (event == OL_OP_OBJECT_MODE_ENTER) { + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_object_mode_enter_cb); + str = "Enter Current Mode"; + } + else if (event == OL_OP_OBJECT_MODE_EXIT) { + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_object_mode_exit_cb); + str = "Exit Current Mode"; + } else { BLI_assert(0); return OPERATOR_CANCELLED; @@ -1039,114 +1055,12 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot) /* **************************************** */ -typedef enum eOutliner_PropGroupOps { - OL_GROUPOP_UNLINK = 1, - OL_GROUPOP_LOCAL, - 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_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_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)); - 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_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; - 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 { OUTLINER_IDOP_INVALID = 0, OUTLINER_IDOP_UNLINK, OUTLINER_IDOP_LOCAL, + OUTLINER_IDOP_STATIC_OVERRIDE, OUTLINER_IDOP_SINGLE, OUTLINER_IDOP_DELETE, OUTLINER_IDOP_REMAP, @@ -1162,6 +1076,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", @@ -1193,6 +1109,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) case OUTLINER_IDOP_UNLINK: { /* 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) { case ID_AC: outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_action_cb, NULL); @@ -1218,6 +1142,12 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL); ED_undo_push(C, "Unlink world"); 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: BKE_report(op->reports, RPT_WARNING, "Not yet implemented"); break; @@ -1231,6 +1161,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, "Overridden Data"); + break; + } case OUTLINER_IDOP_SINGLE: { /* make single user */ @@ -1630,7 +1567,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; @@ -1657,8 +1594,8 @@ void OUTLINER_OT_animdata_operation(wmOperatorType *ot) /* **************************************** */ static const EnumPropertyItem prop_constraint_op_types[] = { - {OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_RESTRICT_VIEW_OFF, "Enable", ""}, - {OL_CONSTRAINTOP_DISABLE, "DISABLE", ICON_RESTRICT_VIEW_ON, "Disable", ""}, + {OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_HIDE_OFF, "Enable", ""}, + {OL_CONSTRAINTOP_DISABLE, "DISABLE", ICON_HIDE_ON, "Disable", ""}, {OL_CONSTRAINTOP_DELETE, "DELETE", ICON_X, "Delete", ""}, {0, NULL, 0, NULL, NULL} }; @@ -1847,6 +1784,26 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot) /* ******************** */ +static int outliner_operator_menu(bContext *C, const char *opname) +{ + wmOperatorType *ot = WM_operatortype_find(opname, false); + uiPopupMenu *pup = UI_popup_menu_begin(C, RNA_struct_ui_name(ot->srna), ICON_NONE); + uiLayout *layout = UI_popup_menu_layout(pup); + + /* set this so the default execution context is the same as submenus */ + uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN); + uiItemsEnumO(layout, ot->idname, RNA_property_identifier(ot->prop)); + + MenuType *mt = WM_menutype_find("OUTLINER_MT_context", false); + if (mt) { + uiItemS(layout); + UI_menutype_draw(C, mt, layout); + } + + UI_popup_menu_end(C, pup); + + return OPERATOR_INTERFACE; +} static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soops, TreeElement *te, const float mval[2]) @@ -1864,9 +1821,10 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop outliner_flag_set(&soops->tree, TSE_SELECTED, 0); tselem->flag |= TSE_SELECTED; - /* redraw, same as outliner_select function */ - soops->storeflag |= SO_TREESTORE_REDRAW; - ED_region_tag_redraw(ar); + + /* Only redraw, don't rebuild here because TreeElement pointers will + * become invalid and operations will crash. */ + ED_region_tag_redraw_no_rebuild(ar); } set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); @@ -1874,28 +1832,32 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop if (scenelevel) { if (objectlevel || datalevel || idlevel) { BKE_report(reports, RPT_WARNING, "Mixed selection"); + return OPERATOR_CANCELLED; } else { - WM_operator_name_call(C, "OUTLINER_OT_scene_operation", WM_OP_INVOKE_REGION_WIN, NULL); + return outliner_operator_menu(C, "OUTLINER_OT_scene_operation"); } } 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_object", WM_OP_INVOKE_REGION_WIN); + return OPERATOR_FINISHED; } else if (idlevel) { if (idlevel == -1 || datalevel) { BKE_report(reports, RPT_WARNING, "Mixed selection"); + return OPERATOR_CANCELLED; } else { switch (idlevel) { 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); + return OPERATOR_FINISHED; break; case ID_LI: - WM_operator_name_call(C, "OUTLINER_OT_lib_operation", WM_OP_INVOKE_REGION_WIN, NULL); + return outliner_operator_menu(C, "OUTLINER_OT_lib_operation"); break; default: - WM_operator_name_call(C, "OUTLINER_OT_id_operation", WM_OP_INVOKE_REGION_WIN, NULL); + return outliner_operator_menu(C, "OUTLINER_OT_id_operation"); break; } } @@ -1903,38 +1865,49 @@ static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOops *soop else if (datalevel) { if (datalevel == -1) { BKE_report(reports, RPT_WARNING, "Mixed selection"); + return OPERATOR_CANCELLED; } else { - if (datalevel == TSE_ANIM_DATA) - WM_operator_name_call(C, "OUTLINER_OT_animdata_operation", WM_OP_INVOKE_REGION_WIN, NULL); + if (datalevel == TSE_ANIM_DATA) { + return outliner_operator_menu(C, "OUTLINER_OT_animdata_operation"); + } else if (datalevel == TSE_DRIVER_BASE) { /* do nothing... no special ops needed yet */ + return OPERATOR_CANCELLED; } - else if (ELEM(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)) { - /*WM_operator_name_call(C, "OUTLINER_OT_renderdata_operation", WM_OP_INVOKE_REGION_WIN, NULL)*/ + else if (datalevel == TSE_LAYER_COLLECTION) { + WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN); + return OPERATOR_FINISHED; + } + else if (ELEM(datalevel, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { + WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN); + return OPERATOR_FINISHED; } else if (datalevel == TSE_ID_BASE) { /* do nothing... there are no ops needed here yet */ } else if (datalevel == TSE_CONSTRAINT) { - WM_operator_name_call(C, "OUTLINER_OT_constraint_operation", WM_OP_INVOKE_REGION_WIN, NULL); + return outliner_operator_menu(C, "OUTLINER_OT_constraint_operation"); } else if (datalevel == TSE_MODIFIER) { - WM_operator_name_call(C, "OUTLINER_OT_modifier_operation", WM_OP_INVOKE_REGION_WIN, NULL); + return outliner_operator_menu(C, "OUTLINER_OT_modifier_operation"); } else { - WM_operator_name_call(C, "OUTLINER_OT_data_operation", WM_OP_INVOKE_REGION_WIN, NULL); + return outliner_operator_menu(C, "OUTLINER_OT_data_operation"); } } } - return 1; + return 0; } for (te = te->subtree.first; te; te = te->next) { - if (do_outliner_operation_event(C, ar, soops, te, mval)) - return 1; + int retval = do_outliner_operation_event(C, ar, soops, te, mval); + if (retval) { + return retval; + } } + return 0; } @@ -1954,18 +1927,26 @@ static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent 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) { - if (do_outliner_operation_event(C, ar, soops, te, fmval)) { - break; + int retval = do_outliner_operation_event(C, ar, soops, te, fmval); + if (retval) { + return retval; } } + /* Menus for clicking in empty space. */ + if (soops->outlinevis == SO_VIEW_LAYER) { + WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN); + return OPERATOR_FINISHED; + } + + WM_menu_name_call(C, "OUTLINER_MT_context", WM_OP_INVOKE_REGION_WIN); return OPERATOR_FINISHED; } /* Menu only! Calls other operators */ void OUTLINER_OT_operation(wmOperatorType *ot) { - ot->name = "Execute Operation"; + ot->name = "Context Menu"; ot->idname = "OUTLINER_OT_operation"; ot->description = "Context menu for item operations"; |