diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index 5f95a69ed1e..52d5405ec0a 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -81,6 +81,7 @@ struct LayerCollection *BKE_layer_collection_get_active_ensure(struct Scene *sce int BKE_layer_collection_count(struct SceneLayer *sl); +struct LayerCollection *BKE_layer_collection_from_index(struct SceneLayer *sl, const int index); int BKE_layer_collection_findindex(struct SceneLayer *sl, const struct LayerCollection *lc); bool BKE_layer_collection_move_above(const struct Scene *scene, struct LayerCollection *lc_dst, struct LayerCollection *lc_src); @@ -93,6 +94,9 @@ struct LayerCollection *BKE_collection_link(struct SceneLayer *sl, struct SceneC void BKE_collection_unlink(struct SceneLayer *sl, struct LayerCollection *lc); +void BKE_collection_enable(struct SceneLayer *sl, struct LayerCollection *lc); +void BKE_collection_disable(struct SceneLayer *sl, struct LayerCollection *lc); + bool BKE_scene_layer_has_collection(struct SceneLayer *sl, const struct SceneCollection *sc); bool BKE_scene_has_object(struct Scene *scene, struct Object *ob); diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 16a4477977f..5d0cb6ae430 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -57,6 +57,7 @@ /* prototype */ struct EngineSettingsCB_Type; static void layer_collection_free(SceneLayer *sl, LayerCollection *lc); +static void layer_collection_objects_populate(SceneLayer *sl, LayerCollection *lc, ListBase *objects); static LayerCollection *layer_collection_add(SceneLayer *sl, LayerCollection *parent, SceneCollection *sc); static LayerCollection *find_layer_collection_by_scene_collection(LayerCollection *lc, const SceneCollection *sc); static IDProperty *collection_engine_settings_create(struct EngineSettingsCB_Type *ces_type, const bool populate); @@ -288,11 +289,7 @@ static Base *object_base_add(SceneLayer *sl, Object *ob) /* LayerCollection */ -/** - * When freeing the entire SceneLayer at once we don't bother with unref - * otherwise SceneLayer is passed to keep the syncing of the LayerCollection tree - */ -static void layer_collection_free(SceneLayer *sl, LayerCollection *lc) +static void layer_collection_objects_unpopulate(SceneLayer *sl, LayerCollection *lc) { if (sl) { for (LinkData *link = lc->object_bases.first; link; link = link->next) { @@ -301,6 +298,15 @@ static void layer_collection_free(SceneLayer *sl, LayerCollection *lc) } BLI_freelistN(&lc->object_bases); +} + +/** + * When freeing the entire SceneLayer at once we don't bother with unref + * otherwise SceneLayer is passed to keep the syncing of the LayerCollection tree + */ +static void layer_collection_free(SceneLayer *sl, LayerCollection *lc) +{ + layer_collection_objects_unpopulate(sl, lc); BLI_freelistN(&lc->overrides); if (lc->properties) { @@ -351,6 +357,15 @@ static LayerCollection *collection_from_index(ListBase *lb, const int number, in return NULL; } +/** + * Get the collection for a given index + */ +LayerCollection *BKE_layer_collection_from_index(SceneLayer *sl, const int index) +{ + int i = 0; + return collection_from_index(&sl->layer_collections, index, &i); +} + /** * Get the active collection */ @@ -797,6 +812,60 @@ void BKE_collection_unlink(SceneLayer *sl, LayerCollection *lc) sl->active_collection = 0; } +/** + * Recursively enable nested collections + */ +static void layer_collection_enable(SceneLayer *sl, LayerCollection *lc) +{ + layer_collection_objects_populate(sl, lc, &lc->scene_collection->objects); + + for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { + layer_collection_enable(sl, nlc); + } +} + +/** + * Enable collection + * Add its objects bases to SceneLayer + * Depsgraph needs to be rebuilt afterwards + */ +void BKE_collection_enable(SceneLayer *sl, LayerCollection *lc) +{ + if ((lc->flag & COLLECTION_DISABLED) == 0) { + return; + } + + lc->flag &= ~COLLECTION_DISABLED; + layer_collection_enable(sl, lc); +} + +/** + * Recursively disable nested collections + */ +static void layer_collection_disable(SceneLayer *sl, LayerCollection *lc) +{ + layer_collection_objects_unpopulate(sl, lc); + + for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { + layer_collection_disable(sl, nlc); + } +} + +/** + * Disable collection + * Remove all its object bases from SceneLayer + * Depsgraph needs to be rebuilt afterwards + */ +void BKE_collection_disable(SceneLayer *sl, LayerCollection *lc) +{ + if ((lc->flag & COLLECTION_DISABLED) != 0) { + return; + } + + lc->flag |= COLLECTION_DISABLED; + layer_collection_disable(sl, lc); +} + static void layer_collection_object_add(SceneLayer *sl, LayerCollection *lc, Object *ob) { Base *base = object_base_add(sl, ob); diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 2db87df8809..092909cbcba 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -27,6 +27,7 @@ #include "BKE_context.h" #include "BKE_collection.h" #include "BKE_layer.h" +#include "BKE_main.h" #include "BKE_report.h" #include "DEG_depsgraph.h" @@ -403,6 +404,82 @@ void OUTLINER_OT_collection_select(wmOperatorType *ot) "Index of collection to select", 0, INT_MAX); } +#define ACTION_DISABLE 0 +#define ACTION_ENABLE 1 +#define ACTION_TOGGLE 2 + +static int collection_toggle_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + SceneLayer *scene_layer = CTX_data_scene_layer(C); + int action = RNA_enum_get(op->ptr, "action"); + LayerCollection *layer_collection = CTX_data_layer_collection(C); + + if (layer_collection->flag & COLLECTION_DISABLED) { + if (ELEM(action, ACTION_TOGGLE, ACTION_ENABLE)) { + BKE_collection_enable(scene_layer, layer_collection); + } + else { /* ACTION_DISABLE */ + BKE_reportf(op->reports, RPT_ERROR, "Layer collection %s already disabled", + layer_collection->scene_collection->name); + return OPERATOR_CANCELLED; + } + } + else { + if (ELEM(action, ACTION_TOGGLE, ACTION_DISABLE)) { + BKE_collection_disable(scene_layer, layer_collection); + } + else { /* ACTION_ENABLE */ + BKE_reportf(op->reports, RPT_ERROR, "Layer collection %s already enabled", + layer_collection->scene_collection->name); + return OPERATOR_CANCELLED; + } + } + + 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_OB_SELECT, scene); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_toggle(wmOperatorType *ot) +{ + PropertyRNA *prop; + + static EnumPropertyItem actions_items[] = { + {ACTION_DISABLE, "DISABLE", 0, "Disable", "Disable selected markers"}, + {ACTION_ENABLE, "ENABLE", 0, "Enable", "Enable selected markers"}, + {ACTION_TOGGLE, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"}, + {0, NULL, 0, NULL, NULL} + }; + + /* identifiers */ + ot->name = "Toggle Collection"; + ot->idname = "OUTLINER_OT_collection_toggle"; + ot->description = "Deselect collection objects"; + + /* api callbacks */ + ot->exec = collection_toggle_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_int(ot->srna, "collection_index", -1, -1, INT_MAX, "Collection Index", "Index of collection to toggle", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_enum(ot->srna, "action", actions_items, ACTION_TOGGLE, "Action", "Selection action to execute"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + +#undef ACTION_TOGGLE +#undef ACTION_ENABLE +#undef ACTION_DISABLE + /* -------------------------------------------------------------------- */ static int stubs_invoke(bContext *UNUSED(C), wmOperator *op, const wmEvent *UNUSED(event)) diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index de820114159..c2414ec6413 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -59,6 +59,7 @@ #include "BKE_object.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" #include "ED_armature.h" #include "ED_keyframing.h" @@ -246,6 +247,30 @@ static void restrictbutton_gp_layer_flag_cb(bContext *C, void *UNUSED(poin), voi WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } +static void enablebutton_collection_flag_cb(bContext *C, void *poin, void *poin2) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = poin; + LayerCollection *layer_collection = poin2; + SceneLayer *scene_layer = BKE_scene_layer_find_from_collection(scene, layer_collection); + + /* We need to toggle the flag since this is called after the flag is already set. */ + layer_collection->flag ^= COLLECTION_DISABLED; + + if (layer_collection->flag & COLLECTION_DISABLED) { + BKE_collection_enable(scene_layer, layer_collection); + } + else { + BKE_collection_disable(scene_layer, layer_collection); + } + + 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_OB_SELECT, scene); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL); +} + static void restrictbutton_collection_flag_cb(bContext *C, void *poin, void *UNUSED(poin2)) { Scene *scene = poin; @@ -559,8 +584,18 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar else if (tselem->type == TSE_LAYER_COLLECTION) { LayerCollection *collection = te->directdata; + const bool is_enabled = (collection->flag & COLLECTION_DISABLED) == 0; + UI_block_emboss_set(block, UI_EMBOSS_NONE); + bt = uiDefIconButBitS(block, UI_BTYPE_BUT_TOGGLE, COLLECTION_DISABLED, 0, + is_enabled ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_ENABLEX), te->ys, UI_UNIT_X, + UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, + TIP_("Enable/Disable collection from depsgraph")); + UI_but_func_set(bt, enablebutton_collection_flag_cb, scene, collection); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_VISIBLE, 0, ICON_RESTRICT_VIEW_OFF, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index f046e1c3176..8d93f6bca55 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -144,11 +144,12 @@ typedef enum { /* size constants */ #define OL_Y_OFFSET 2 -#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 3.0f) -#define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 2.0f) +#define OL_TOG_RESTRICT_ENABLEX (UI_UNIT_X * 3.0f) +#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 2.0f) +#define OL_TOG_RESTRICT_SELECTX UI_UNIT_X #define OL_TOG_RESTRICT_RENDERX UI_UNIT_X -#define OL_TOGW OL_TOG_RESTRICT_VIEWX +#define OL_TOGW OL_TOG_RESTRICT_ENABLEX #define OL_RNA_COLX (UI_UNIT_X * 15) #define OL_RNA_COL_SIZEX (UI_UNIT_X * 7.5f) @@ -318,6 +319,7 @@ struct SceneCollection *outliner_scene_collection_from_tree_element(TreeElement void OUTLINER_OT_collections_delete(struct wmOperatorType *ot); void OUTLINER_OT_collection_select(struct wmOperatorType *ot); +void OUTLINER_OT_collection_toggle(struct wmOperatorType *ot); void OUTLINER_OT_collection_link(struct wmOperatorType *ot); void OUTLINER_OT_collection_unlink(struct wmOperatorType *ot); void OUTLINER_OT_collection_new(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 5466ef1a9ed..6946993d630 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -328,6 +328,7 @@ void outliner_operatortypes(void) /* collections */ WM_operatortype_append(OUTLINER_OT_collections_delete); WM_operatortype_append(OUTLINER_OT_collection_select); + WM_operatortype_append(OUTLINER_OT_collection_toggle); WM_operatortype_append(OUTLINER_OT_collection_link); WM_operatortype_append(OUTLINER_OT_collection_unlink); WM_operatortype_append(OUTLINER_OT_collection_new); diff --git a/source/blender/makesdna/DNA_layer_types.h b/source/blender/makesdna/DNA_layer_types.h index 03ca6cd8c5c..7ef6e8c34dd 100644 --- a/source/blender/makesdna/DNA_layer_types.h +++ b/source/blender/makesdna/DNA_layer_types.h @@ -114,6 +114,7 @@ enum { enum { COLLECTION_VISIBLE = (1 << 0), COLLECTION_SELECTABLE = (1 << 1), + COLLECTION_DISABLED = (1 << 2), }; /* SceneLayer->flag */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 119432f7ed3..9887da153e8 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -2899,6 +2899,39 @@ static void rna_LayerCollection_flag_update(bContext *C, PointerRNA *UNUSED(ptr) WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } +static void rna_LayerCollection_enable_set( + ID *id, LayerCollection *layer_collection, Main *bmain, bContext *C, ReportList *reports, int value) +{ + Scene *scene = (Scene *)id; + SceneLayer *scene_layer = BKE_scene_layer_find_from_collection(scene, layer_collection); + + if (layer_collection->flag & COLLECTION_DISABLED) { + if (value == 1) { + BKE_collection_enable(scene_layer, layer_collection); + } + else { + BKE_reportf(reports, RPT_ERROR, "Layer collection '%s' is already disabled", + layer_collection->scene_collection->name); + return; + } + } + else { + if (value == 0) { + BKE_collection_disable(scene_layer, layer_collection); + } + else { + BKE_reportf(reports, RPT_ERROR, "Layer collection '%s' is already enabled", + layer_collection->scene_collection->name); + } + } + + 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_OB_SELECT, scene); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); +} + static int rna_LayerCollections_active_collection_index_get(PointerRNA *ptr) { SceneLayer *sl = (SceneLayer *)ptr->data; @@ -6991,7 +7024,17 @@ static void rna_def_layer_collection(BlenderRNA *brna) parm = RNA_def_boolean(func, "result", false, "Result", "Whether the operation succeded"); RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "enable_set", "rna_LayerCollection_enable_set"); + RNA_def_function_ui_description(func, "Enable or disable a collection"); + parm = RNA_def_boolean(func, "value", 1, "Enable", ""); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_USE_CONTEXT | FUNC_USE_REPORTS); + /* Flags */ + prop = RNA_def_property(srna, "is_enabled", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_DISABLED); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Enabled", "Enable or disable collection from depsgraph"); + prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_VISIBLE); RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);