Collection duplication from Outliner: add a 'duplicate hierarchy' operation.
Point is, you may want to duplicate your set of collections, but not duplicate all their objects. Some notes: * Am rather skeptical about the practice of using operator name to define behavior of some common exec code. Imho, that should be a single operator with an enum to refine its behavior (@cambpellbarton may also have an opinion here?). Left it as-is for now, because this seems to be used by other operators too in that code. :/ * @dfelinto, @pablovazquez, @billreynish am not so happy with current names, but cannot find really good short ones either... Also, shouldn't we move those into a dedicated `Duplicate` sub-menu?
This commit is contained in:
parent
8462f0e85e
commit
a77feabb51
|
@ -192,8 +192,9 @@ class OUTLINER_MT_collection(Menu):
|
|||
space = context.space_data
|
||||
|
||||
layout.operator("outliner.collection_new", text="New").nested = True
|
||||
layout.operator("outliner.collection_duplicate", text="Duplicate Collection")
|
||||
layout.operator("outliner.collection_duplicate_hierarchy", text="Duplicate Hierarchy")
|
||||
layout.operator("outliner.collection_duplicate_linked", text="Duplicate Linked")
|
||||
layout.operator("outliner.collection_duplicate", text="Duplicate Full")
|
||||
|
||||
layout.separator()
|
||||
|
||||
|
|
|
@ -57,7 +57,9 @@ struct Collection *BKE_collection_copy(struct Main *bmain, struct Collection *pa
|
|||
void BKE_collection_copy_data(struct Main *bmain, struct Collection *collection_dst, const struct Collection *collection_src, const int flag);
|
||||
void BKE_collection_make_local(struct Main *bmain, struct Collection *collection, const bool lib_local);
|
||||
|
||||
struct Collection *BKE_collection_duplicate(struct Main *bmain, struct Collection *parent, struct Collection *collection, const bool do_hierarchy, const bool do_deep_copy);
|
||||
struct Collection *BKE_collection_duplicate(
|
||||
struct Main *bmain, struct Collection *parent, struct Collection *collection,
|
||||
const bool do_hierarchy, const bool do_objects, const bool do_obdata);
|
||||
struct Collection *BKE_collection_copy_master(struct Main *bmain, struct Collection *collection, const int flag);
|
||||
|
||||
/* Master Collection for Scene */
|
||||
|
|
|
@ -211,11 +211,12 @@ void BKE_collection_copy_data(
|
|||
}
|
||||
|
||||
static Collection *collection_duplicate_recursive(
|
||||
Main *bmain, Collection *parent, Collection *collection_old, const bool do_hierarchy, const bool do_deep_copy)
|
||||
Main *bmain, Collection *parent, Collection *collection_old,
|
||||
const bool do_hierarchy, const bool do_objects, const bool do_obdata)
|
||||
{
|
||||
Collection *collection_new;
|
||||
bool do_full_process = false;
|
||||
const int object_dupflag = (do_deep_copy) ? U.dupflag : 0;
|
||||
const int object_dupflag = (do_obdata) ? U.dupflag : 0;
|
||||
|
||||
if (!do_hierarchy || collection_old->id.newid == NULL) {
|
||||
BKE_id_copy(bmain, &collection_old->id, (ID **)&collection_new);
|
||||
|
@ -250,19 +251,21 @@ static Collection *collection_duplicate_recursive(
|
|||
return collection_new;
|
||||
}
|
||||
|
||||
/* We can loop on collection_old's objects, that list is currently identical the collection_new' objects,
|
||||
* and won't be changed here. */
|
||||
for (CollectionObject *cob = collection_old->gobject.first; cob; cob = cob->next) {
|
||||
Object *ob_old = cob->ob;
|
||||
Object *ob_new = (Object *)ob_old->id.newid;
|
||||
if (do_objects) {
|
||||
/* We can loop on collection_old's objects, that list is currently identical the collection_new' objects,
|
||||
* and won't be changed here. */
|
||||
for (CollectionObject *cob = collection_old->gobject.first; cob; cob = cob->next) {
|
||||
Object *ob_old = cob->ob;
|
||||
Object *ob_new = (Object *)ob_old->id.newid;
|
||||
|
||||
if (ob_new == NULL) {
|
||||
ob_new = BKE_object_duplicate(bmain, ob_old, object_dupflag);
|
||||
ID_NEW_SET(ob_old, ob_new);
|
||||
if (ob_new == NULL) {
|
||||
ob_new = BKE_object_duplicate(bmain, ob_old, object_dupflag);
|
||||
ID_NEW_SET(ob_old, ob_new);
|
||||
}
|
||||
|
||||
collection_object_add(bmain, collection_new, ob_new, 0, true);
|
||||
collection_object_remove(bmain, collection_new, ob_old, false);
|
||||
}
|
||||
|
||||
collection_object_add(bmain, collection_new, ob_new, 0, true);
|
||||
collection_object_remove(bmain, collection_new, ob_old, false);
|
||||
}
|
||||
|
||||
/* We can loop on collection_old's children, that list is currently identical the collection_new' children,
|
||||
|
@ -270,7 +273,7 @@ static Collection *collection_duplicate_recursive(
|
|||
for (CollectionChild *child = collection_old->children.first; child; child = child->next) {
|
||||
Collection *child_collection_old = child->collection;
|
||||
|
||||
collection_duplicate_recursive(bmain, collection_new, child_collection_old, do_hierarchy, do_deep_copy);
|
||||
collection_duplicate_recursive(bmain, collection_new, child_collection_old, do_hierarchy, do_objects, do_obdata);
|
||||
collection_child_remove(collection_new, child_collection_old);
|
||||
}
|
||||
|
||||
|
@ -285,7 +288,7 @@ static Collection *collection_duplicate_recursive(
|
|||
*/
|
||||
Collection *BKE_collection_copy(Main *bmain, Collection *parent, Collection *collection)
|
||||
{
|
||||
return BKE_collection_duplicate(bmain, parent, collection, false, false);
|
||||
return BKE_collection_duplicate(bmain, parent, collection, false, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -296,11 +299,12 @@ Collection *BKE_collection_copy(Main *bmain, Collection *parent, Collection *col
|
|||
* \warning If any 'deep copy' behavior is enabled, this functions will clear all \a bmain id.idnew pointers.
|
||||
*
|
||||
* \param do_hierarchy If true, it will recursively make shallow copies of children collections and objects.
|
||||
* \param do_deep_copy If true, it will also make deep duplicates of objects, using behavior defined in user settings
|
||||
* (U.dupflag). This one does nothing if \a do_hierarchy is not set.
|
||||
* \param do_obdata If true, it will also make deep duplicates of objects, using behavior defined in user settings
|
||||
* (U.dupflag). This one does nothing if \a do_hierarchy is not set.
|
||||
*/
|
||||
Collection *BKE_collection_duplicate(
|
||||
Main *bmain, Collection *parent, Collection *collection, const bool do_hierarchy, const bool do_deep_copy)
|
||||
Main *bmain, Collection *parent, Collection *collection,
|
||||
const bool do_hierarchy, const bool do_objects, const bool do_obdata)
|
||||
{
|
||||
/* It's not allowed to copy the master collection. */
|
||||
if (collection->flag & COLLECTION_IS_MASTER) {
|
||||
|
@ -314,7 +318,7 @@ Collection *BKE_collection_duplicate(
|
|||
}
|
||||
|
||||
Collection *collection_new = collection_duplicate_recursive(
|
||||
bmain, parent, collection, do_hierarchy, do_deep_copy);
|
||||
bmain, parent, collection, do_hierarchy, do_objects, do_obdata);
|
||||
|
||||
/* This code will follows into all ID links using an ID tagged with LIB_TAG_NEW.*/
|
||||
BKE_libblock_relink_to_newid(&collection_new->id);
|
||||
|
|
|
@ -448,7 +448,8 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op)
|
|||
Main *bmain = CTX_data_main(C);
|
||||
SpaceOutliner *soops = CTX_wm_space_outliner(C);
|
||||
TreeElement *te = outliner_active_collection(C);
|
||||
bool linked = strstr(op->idname, "linked") != NULL;
|
||||
const bool hierarchy = strstr(op->idname, "hierarchy") != NULL;
|
||||
const bool linked = strstr(op->idname, "linked") != NULL;
|
||||
|
||||
/* Can happen when calling from a key binding. */
|
||||
if (te == NULL) {
|
||||
|
@ -468,7 +469,7 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op)
|
|||
case SO_SCENES:
|
||||
case SO_VIEW_LAYER:
|
||||
case SO_LIBRARIES:
|
||||
BKE_collection_duplicate(bmain, parent, collection, true, !linked);
|
||||
BKE_collection_duplicate(bmain, parent, collection, true, !hierarchy, !linked);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -478,12 +479,12 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op)
|
|||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void OUTLINER_OT_collection_duplicate(wmOperatorType *ot)
|
||||
void OUTLINER_OT_collection_duplicate_hierarchy(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Duplicate Collection";
|
||||
ot->idname = "OUTLINER_OT_collection_duplicate";
|
||||
ot->description = "Duplicate all objects and collections and make them single user";
|
||||
ot->name = "Duplicate Collection Hierarchy";
|
||||
ot->idname = "OUTLINER_OT_collection_duplicate_hierarchy";
|
||||
ot->description = "Recursively duplicate the collection and all its children, with linked objects";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = collection_duplicate_exec;
|
||||
|
@ -498,7 +499,22 @@ void OUTLINER_OT_collection_duplicate_linked(wmOperatorType *ot)
|
|||
/* identifiers */
|
||||
ot->name = "Duplicate Linked Collection";
|
||||
ot->idname = "OUTLINER_OT_collection_duplicate_linked";
|
||||
ot->description = "Duplicate all objects and collections with linked object data";
|
||||
ot->description = "Recursively duplicate the collection, all its children and objects, with linked object data";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = collection_duplicate_exec;
|
||||
ot->poll = ED_outliner_collections_editor_poll;
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
void OUTLINER_OT_collection_duplicate(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name = "Duplicate Collection";
|
||||
ot->idname = "OUTLINER_OT_collection_duplicate";
|
||||
ot->description = "Recursively duplicate the collection, all its children, objects and object data";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec = collection_duplicate_exec;
|
||||
|
|
|
@ -315,8 +315,9 @@ bool outliner_is_collection_tree_element(const TreeElement *te);
|
|||
struct Collection *outliner_collection_from_tree_element(const TreeElement *te);
|
||||
|
||||
void OUTLINER_OT_collection_new(struct wmOperatorType *ot);
|
||||
void OUTLINER_OT_collection_duplicate(struct wmOperatorType *ot);
|
||||
void OUTLINER_OT_collection_duplicate_hierarchy(struct wmOperatorType *ot);
|
||||
void OUTLINER_OT_collection_duplicate_linked(struct wmOperatorType *ot);
|
||||
void OUTLINER_OT_collection_duplicate(struct wmOperatorType *ot);
|
||||
void OUTLINER_OT_collection_delete(struct wmOperatorType *ot);
|
||||
void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot);
|
||||
void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot);
|
||||
|
|
|
@ -93,8 +93,9 @@ void outliner_operatortypes(void)
|
|||
|
||||
/* collections */
|
||||
WM_operatortype_append(OUTLINER_OT_collection_new);
|
||||
WM_operatortype_append(OUTLINER_OT_collection_duplicate);
|
||||
WM_operatortype_append(OUTLINER_OT_collection_duplicate_hierarchy);
|
||||
WM_operatortype_append(OUTLINER_OT_collection_duplicate_linked);
|
||||
WM_operatortype_append(OUTLINER_OT_collection_duplicate);
|
||||
WM_operatortype_append(OUTLINER_OT_collection_delete);
|
||||
WM_operatortype_append(OUTLINER_OT_collection_objects_select);
|
||||
WM_operatortype_append(OUTLINER_OT_collection_objects_deselect);
|
||||
|
|
Loading…
Reference in New Issue