diff options
author | Dalai Felinto <dfelinto@gmail.com> | 2018-02-02 02:11:59 +0300 |
---|---|---|
committer | Dalai Felinto <dfelinto@gmail.com> | 2018-02-02 17:25:05 +0300 |
commit | c7c070c2ece0f41772cbcfe3445f3e0be684dd1d (patch) | |
tree | 28f43537045a31a7a7b5c3d75d35035a73277de0 /source/blender/editors | |
parent | a4d2b102f313b8d427e6ff6066f38cc3a2394628 (diff) |
Collections: Operator to duplicate a collection
When duplicating a layer collection directly linked to the view layer we copy
the collection and link it.
For all the not directly linked layer collectionns, we try to sync the layer
collection flags, overrides, ...
Also we make sure the new collection is right after the original collection.
We also expose this in RNA, via collection.duplicate().
Diffstat (limited to 'source/blender/editors')
4 files changed, 89 insertions, 0 deletions
diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 394a7a80b39..89f1240f86d 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -91,6 +91,12 @@ static int view_layer_editor_poll(bContext *C) return (so != NULL) && (so->outlinevis == SO_VIEW_LAYER); } +static int outliner_either_collection_editor_poll(bContext *C) +{ + SpaceOops *so = CTX_wm_space_outliner(C); + return (so != NULL) && (ELEM(so->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS)); +} + /* -------------------------------------------------------------------- */ /* collection manager operators */ @@ -819,3 +825,77 @@ void OUTLINER_OT_collection_objects_select(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +struct CollectionDuplicateData { + TreeElement *te; +}; + +static TreeTraversalAction outliner_find_first_selected_collection(TreeElement *te, void *customdata) +{ + struct CollectionDuplicateData *data = customdata; + TreeStoreElem *tselem = TREESTORE(te); + + switch (tselem->type) { + case TSE_LAYER_COLLECTION: + case TSE_SCENE_COLLECTION: + data->te = te; + return TRAVERSE_BREAK; + case TSE_LAYER_COLLECTION_BASE: + default: + return TRAVERSE_CONTINUE; + } +} + +static TreeElement *outliner_active_collection(bContext *C) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + + struct CollectionDuplicateData data = { + .te = NULL, + }; + + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_collection, &data); + return data.te; +} + +static int collection_duplicate_exec(bContext *C, wmOperator *op) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + TreeElement *te = outliner_active_collection(C); + + BLI_assert(te != NULL); + if (BKE_collection_master(TREESTORE(te)->id) == outliner_scene_collection_from_tree_element(te)) { + BKE_report(op->reports, RPT_ERROR, "You can't duplicate the master collection"); + return OPERATOR_CANCELLED; + } + + switch (soops->outlinevis) { + case SO_COLLECTIONS: + BKE_collection_duplicate(TREESTORE(te)->id, (SceneCollection *)te->directdata); + break; + case SO_VIEW_LAYER: + case SO_GROUPS: + BKE_layer_collection_duplicate(TREESTORE(te)->id, (LayerCollection *)te->directdata); + break; + } + + DEG_relations_tag_update(CTX_data_main(C)); + WM_main_add_notifier(NC_SCENE | ND_LAYER, CTX_data_scene(C)); + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_collection_duplicate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Duplicate Collection"; + ot->idname = "OUTLINER_OT_collection_duplicate"; + ot->description = "Duplicate collection"; + + /* api callbacks */ + ot->exec = collection_duplicate_exec; + ot->poll = outliner_either_collection_editor_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 06d06d66326..ab10e5a3036 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -344,6 +344,7 @@ 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); +void OUTLINER_OT_collection_duplicate(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_remove(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index b5b4fbbf039..eb42fe47cbf 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -474,6 +474,7 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_collection_link); WM_operatortype_append(OUTLINER_OT_collection_unlink); WM_operatortype_append(OUTLINER_OT_collection_new); + WM_operatortype_append(OUTLINER_OT_collection_duplicate); WM_operatortype_append(OUTLINER_OT_collection_nested_new); WM_operatortype_append(OUTLINER_OT_collection_delete_selected); diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index c4d032e34ee..3ee0d011bbb 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -677,6 +677,7 @@ typedef enum eOutliner_PropCollectionOps { 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, @@ -875,6 +876,11 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel } 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); @@ -1851,6 +1857,7 @@ static EnumPropertyItem prop_collection_op_types[] = { {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"}, |