diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/BKE_collection.h | 4 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_layer.h | 9 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/collection.c | 146 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/layer.c | 101 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_tree.c | 19 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_scene.c | 83 |
6 files changed, 344 insertions, 18 deletions
diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h index e090584ad7a..2ea2c23dadd 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -55,6 +55,10 @@ void BKE_collections_object_remove(struct Main *bmain, struct Scene *scene, stru void BKE_collection_reinsert_after(const struct Scene *scene, struct SceneCollection *sc_reinsert, struct SceneCollection *sc_after); void BKE_collection_reinsert_into(struct SceneCollection *sc_reinsert, struct SceneCollection *sc_into); +bool BKE_collection_move_above(const struct Scene *scene, struct SceneCollection *sc_dst, struct SceneCollection *sc_src); +bool BKE_collection_move_below(const struct Scene *scene, struct SceneCollection *sc_dst, struct SceneCollection *sc_src); +bool BKE_collection_move_into(const struct Scene *scene, struct SceneCollection *sc_dst, struct SceneCollection *sc_src); + typedef void (*BKE_scene_objects_Cb)(struct Object *ob, void *data); typedef void (*BKE_scene_collections_Cb)(struct SceneCollection *ob, void *data); diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index aa1d537a28e..14324f27bfe 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -84,9 +84,14 @@ struct LayerCollection *BKE_layer_collection_active(struct SceneLayer *sl); int BKE_layer_collection_count(struct SceneLayer *sl); int BKE_layer_collection_findindex(struct SceneLayer *sl, struct LayerCollection *lc); -void BKE_layer_collection_reinsert_after(const struct Scene *scene, struct SceneLayer *sl, +bool BKE_layer_collection_reinsert_after(const struct Scene *scene, struct SceneLayer *sl, struct LayerCollection *lc_reinsert, struct LayerCollection *lc_after); -void BKE_layer_collection_reinsert_into(struct LayerCollection *lc_reinsert, struct LayerCollection *lc_into); + +bool BKE_layer_collection_move_above(const struct Scene *scene, struct LayerCollection *lc_dst, struct LayerCollection *lc_src); +bool BKE_layer_collection_move_below(const struct Scene *scene, struct LayerCollection *lc_dst, struct LayerCollection *lc_src); +bool BKE_layer_collection_move_into(const struct Scene *scene, struct LayerCollection *lc_dst, struct LayerCollection *lc_src); + +void BKE_layer_collection_resync(const struct Scene *scene, const struct SceneCollection *sc); struct LayerCollection *BKE_collection_link(struct SceneLayer *sl, struct SceneCollection *sc); diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index b423efdda24..564fa5d9593 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -298,16 +298,150 @@ void BKE_collections_object_remove(Main *bmain, Scene *scene, Object *ob, const FOREACH_SCENE_COLLECTION_END } -void BKE_collection_reinsert_after(const struct Scene *scene, SceneCollection *sc_reinsert, SceneCollection *sc_after) +/* ---------------------------------------------------------------------- */ +/* Outliner drag and drop */ + +/** + * Find and return the SceneCollection that has \a sc_child as one of its directly + * nested SceneCollection. + * + * \param sc_parent Initial SceneCollection to look into recursively, usually the master collection + */ +static SceneCollection *find_collection_parent(const SceneCollection *sc_child, SceneCollection *sc_parent) +{ + for (SceneCollection *sc_nested = sc_parent->scene_collections.first; sc_nested; sc_nested = sc_nested->next) { + if (sc_nested == sc_child) { + return sc_parent; + } + + SceneCollection *found = find_collection_parent(sc_child, sc_nested); + if (found) { + return found; + } + } + + return NULL; +} + +/** + * Check if \a sc_reference is nested to \a sc_parent SceneCollection + */ +static bool is_collection_in_tree(const SceneCollection *sc_reference, SceneCollection *sc_parent) +{ + return find_collection_parent(sc_reference, sc_parent) != NULL; +} + +bool BKE_collection_move_above(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src) +{ + /* Find the SceneCollection the sc_src belongs to */ + SceneCollection *sc_master = BKE_collection_master(scene); + + /* Master Layer can't be moved around*/ + if (ELEM(sc_master, sc_src, sc_dst)) { + return false; + } + + /* collection is already where we wanted it to be */ + if (sc_dst->prev == sc_src) { + return false; + } + + /* We can't move a collection fs the destiny collection + * is nested to the source collection */ + if (is_collection_in_tree(sc_dst, sc_src)) { + return false; + } + + SceneCollection *sc_src_parent = find_collection_parent(sc_src, sc_master); + SceneCollection *sc_dst_parent = find_collection_parent(sc_dst, sc_master); + BLI_assert(sc_src_parent); + BLI_assert(sc_dst_parent); + + /* Remove sc_src from its parent */ + BLI_remlink(&sc_src_parent->scene_collections, sc_src); + + /* Re-insert it where it belongs */ + BLI_insertlinkbefore(&sc_dst_parent->scene_collections, sc_dst, sc_src); + + /* Update the tree */ + BKE_layer_collection_resync(scene, sc_src_parent); + BKE_layer_collection_resync(scene, sc_dst_parent); + + return true; +} + +bool BKE_collection_move_below(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src) { - UNUSED_VARS(scene, sc_reinsert, sc_after); - TODO_LAYER_OPERATORS; + /* Find the SceneCollection the sc_src belongs to */ + SceneCollection *sc_master = BKE_collection_master(scene); + + /* Master Layer can't be moved around*/ + if (ELEM(sc_master, sc_src, sc_dst)) { + return false; + } + + /* Collection is already where we wanted it to be */ + if (sc_dst->next == sc_src) { + return false; + } + + /* We can't move a collection if the destiny collection + * is nested to the source collection */ + if (is_collection_in_tree(sc_dst, sc_src)) { + return false; + } + + SceneCollection *sc_src_parent = find_collection_parent(sc_src, sc_master); + SceneCollection *sc_dst_parent = find_collection_parent(sc_dst, sc_master); + BLI_assert(sc_src_parent); + BLI_assert(sc_dst_parent); + + /* Remove sc_src from its parent */ + BLI_remlink(&sc_src_parent->scene_collections, sc_src); + + /* Re-insert it where it belongs */ + BLI_insertlinkafter(&sc_dst_parent->scene_collections, sc_dst, sc_src); + + /* Update the tree */ + BKE_layer_collection_resync(scene, sc_src_parent); + BKE_layer_collection_resync(scene, sc_dst_parent); + + return true; } -void BKE_collection_reinsert_into(SceneCollection *sc_reinsert, SceneCollection *sc_into) +bool BKE_collection_move_into(const Scene *scene, SceneCollection *sc_dst, SceneCollection *sc_src) { - UNUSED_VARS(sc_reinsert, sc_into); - TODO_LAYER_OPERATORS; + /* Find the SceneCollection the sc_src belongs to */ + SceneCollection *sc_master = BKE_collection_master(scene); + if (sc_src == sc_master) { + return false; + } + + /* We can't move a collection if the destiny collection + * is nested to the source collection */ + if (is_collection_in_tree(sc_dst, sc_src)) { + return false; + } + + SceneCollection *sc_src_parent = find_collection_parent(sc_src, sc_master); + BLI_assert(sc_src_parent); + + /* collection is already where we wanted it to be */ + if (sc_dst->scene_collections.last == sc_src) { + return false; + } + + /* Remove sc_src from it */ + BLI_remlink(&sc_src_parent->scene_collections, sc_src); + + /* Insert sc_src into sc_dst */ + BLI_addtail(&sc_dst->scene_collections, sc_src); + + /* Update the tree */ + BKE_layer_collection_resync(scene, sc_src_parent); + BKE_layer_collection_resync(scene, sc_dst); + + return true; } /* ---------------------------------------------------------------------- */ diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 77501c4acce..fb1a35d210c 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -533,13 +533,13 @@ static ListBase *scene_collection_listbase_find(ListBase *lb, SceneCollection *s * Move \a lc_reinsert so that it follows \a lc_after. Both have to be stored in \a sl. * \param lc_after: Can be NULL to reinsert \a lc_after as first collection of its own list. */ -void BKE_layer_collection_reinsert_after( +bool BKE_layer_collection_reinsert_after( const Scene *scene, SceneLayer *sl, LayerCollection *lc_reinsert, LayerCollection *lc_after) { /* TODO this function probably needs to be rewritten completely to support all cases * (reinserting master collection, reinsert into different hierarchy levels, etc) */ TODO_LAYER_OPERATORS; - +#if 0 SceneCollection *sc_master = BKE_collection_master(scene); SceneCollection *sc_reinsert = lc_reinsert->scene_collection; ListBase *lc_reinsert_lb = layer_collection_listbase_find(&sl->layer_collections, lc_reinsert); @@ -566,16 +566,107 @@ void BKE_layer_collection_reinsert_after( BKE_scene_layer_base_flag_recalculate(sl); BKE_scene_layer_engine_settings_collection_recalculate(sl, lc_reinsert); +#else + UNUSED_VARS(scene, sl, lc_reinsert, lc_after); + UNUSED_VARS(layer_collection_listbase_find, scene_collection_listbase_find); + return false; +#endif } -void BKE_layer_collection_reinsert_into(LayerCollection *lc_reinsert, LayerCollection *lc_into) +/* ---------------------------------------------------------------------- */ +/* Outliner drag and drop */ + +/** + * Nest a LayerCollection into another one + * Both collections must be from the same SceneLayer, return true if succeded. + * + * The LayerCollection will effectively be moved into the + * new (nested) position. So all the settings, overrides, ... go with it, and + * if the collection was directly linked to the SceneLayer it's then unlinked. + * + * For the other SceneLayers we simply resync the tree, without changing directly + * linked collections (even if they link to the same SceneCollection) + * + * \param lc_src LayerCollection to nest into \a lc_dst + * \param lc_dst LayerCollection to have \a lc_src inserted into + */ +bool BKE_layer_collection_move_into(const Scene *scene, LayerCollection *lc_src, LayerCollection *lc_dst) { /* TODO this is missing */ TODO_LAYER_OPERATORS; - UNUSED_VARS(lc_reinsert, lc_into); + UNUSED_VARS(scene, lc_src, lc_dst); + return false; +} + +bool BKE_layer_collection_move_above(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src) +{ + /* TODO this is missing */ + TODO_LAYER_OPERATORS; + UNUSED_VARS(scene, lc_dst, lc_src); + return false; +} + +bool BKE_layer_collection_move_below(const Scene *scene, LayerCollection *lc_dst, LayerCollection *lc_src) +{ + /* TODO this is missing */ + TODO_LAYER_OPERATORS; + UNUSED_VARS(scene, lc_dst, lc_src); + return false; +} + +static bool layer_collection_resync(SceneLayer *sl, LayerCollection *lc, const SceneCollection *sc) +{ + if (lc->scene_collection == sc) { + ListBase collections = {NULL}; + BLI_movelisttolist(&collections, &lc->layer_collections); + + for (SceneCollection *sc_nested = sc->scene_collections.first; sc_nested; sc_nested = sc_nested->next) { + LayerCollection *lc_nested = BLI_findptr(&collections, sc_nested, offsetof(LayerCollection, scene_collection)); + if (lc_nested) { + BLI_remlink(&collections, lc_nested); + BLI_addtail(&lc->layer_collections, lc_nested); + } + else { + layer_collection_add(sl, &lc->layer_collections, sc_nested); + } + } + + for (LayerCollection *lc_nested = collections.first; lc_nested; lc_nested = lc_nested->next) { + layer_collection_free(sl, lc_nested); + } + BLI_freelistN(&collections); + + BLI_assert(BLI_listbase_count(&lc->layer_collections) == + BLI_listbase_count(&sc->scene_collections)); + + return true; + } + + for (LayerCollection *lc_nested = lc->layer_collections.first; lc_nested; lc_nested = lc_nested->next) { + if (layer_collection_resync(sl, lc_nested, sc)) { + return true; + } + } + + return false; } /** + * Update the scene layers so that any LayerCollection that points + * to \a sc is re-synced again + */ +void BKE_layer_collection_resync(const Scene *scene, const SceneCollection *sc) +{ + for (SceneLayer *sl = scene->render_layers.first; sl; sl = sl->next) { + for (LayerCollection *lc = sl->layer_collections.first; lc; lc = lc->next) { + layer_collection_resync(sl, lc, sc); + } + } +} + +/* ---------------------------------------------------------------------- */ + +/** * Link a collection to a renderlayer * The collection needs to be created separately */ @@ -658,10 +749,10 @@ static LayerCollection *layer_collection_add(SceneLayer *sl, ListBase *lb, Scene layer_collection_create_engine_settings(lc); layer_collection_create_mode_settings(lc); layer_collection_populate(sl, lc, sc); + return lc; } - /* ---------------------------------------------------------------------- */ /** diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index afd9610b6bf..1db530804b7 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1298,21 +1298,30 @@ static void outliner_layer_collections_reorder(const Scene *scene, TreeElement * BKE_layer_collection_reinsert_after(scene, sl, insert_coll, insert_handle_coll); } else if (action == TE_INSERT_INTO) { - BKE_layer_collection_reinsert_into(insert_coll, insert_handle_coll); + BKE_layer_collection_move_into(scene, insert_coll, insert_handle_coll); } } static void outliner_scene_collections_reorder(const Scene *scene, TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action) { - SceneCollection *insert_coll = insert_element->directdata; - SceneCollection *insert_handle_coll = insert_handle ? insert_handle->directdata : NULL; + SceneCollection *sc_src = insert_element->directdata; + SceneCollection *sc_dst = insert_handle ? insert_handle->directdata : NULL; if (action == TE_INSERT_AFTER) { - BKE_collection_reinsert_after(scene, insert_coll, insert_handle_coll); + if (sc_dst == NULL) { + /* It needs a SceneCollection to use as reference, + * specially now that we are to allow insert in collections + * that don't belong to the same hierarchical level*/ + TODO_LAYER_OPERATORS; + /* BKE_collection_move_after(scene, sc_dst, sc_src); */ + } + else { + BKE_collection_move_below(scene, sc_dst, sc_src); + } } else if (action == TE_INSERT_INTO) { - BKE_collection_reinsert_into(insert_coll, insert_handle_coll); + BKE_collection_move_into(scene, sc_dst, sc_src); } } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 75197b78e5c..55b94c244bf 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -2283,6 +2283,24 @@ static PointerRNA rna_SceneCollection_objects_get(CollectionPropertyIterator *it return rna_pointer_inherit_refine(&iter->parent, &RNA_Object, ((LinkData *)internal->link)->data); } +static int rna_SceneCollection_move_above(ID *id, SceneCollection *sc_src, SceneCollection *sc_dst) +{ + Scene *scene = (Scene *)id; + return BKE_collection_move_above(scene, sc_dst, sc_src); +} + +static int rna_SceneCollection_move_below(ID *id, SceneCollection *sc_src, SceneCollection *sc_dst) +{ + Scene *scene = (Scene *)id; + return BKE_collection_move_below(scene, sc_dst, sc_src); +} + +static int rna_SceneCollection_move_into(ID *id, SceneCollection *sc_src, SceneCollection *sc_dst) +{ + Scene *scene = (Scene *)id; + return BKE_collection_move_into(scene, sc_dst, sc_src); +} + static SceneCollection *rna_SceneCollection_new(ID *id, SceneCollection *sc_parent, const char *name) { Scene *scene = (Scene *)id; @@ -2568,6 +2586,24 @@ static PointerRNA rna_LayerCollection_mode_settings_get(ID *UNUSED(id), LayerCol return rna_pointer_inherit_refine(&ptr, &RNA_CollectionModeSettings, ces); } +static int rna_LayerCollection_move_above(ID *id, LayerCollection *lc_src, LayerCollection *lc_dst) +{ + Scene *scene = (Scene *)id; + return BKE_layer_collection_move_above(scene, lc_dst, lc_src); +} + +static int rna_LayerCollection_move_below(ID *id, LayerCollection *lc_src, LayerCollection *lc_dst) +{ + Scene *scene = (Scene *)id; + return BKE_layer_collection_move_below(scene, lc_dst, lc_src); +} + +static int rna_LayerCollection_move_into(ID *id, LayerCollection *lc_src, LayerCollection *lc_dst) +{ + Scene *scene = (Scene *)id; + return BKE_layer_collection_move_into(scene, lc_dst, lc_src); +} + static void rna_LayerCollection_hide_update(bContext *C, PointerRNA *ptr) { Scene *scene = CTX_data_scene(C); @@ -5782,6 +5818,9 @@ static void rna_def_scene_collection(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; + srna = RNA_def_struct(brna, "SceneCollection", NULL); RNA_def_struct_ui_text(srna, "Scene Collection", "Collection"); @@ -5814,6 +5853,28 @@ static void rna_def_scene_collection(BlenderRNA *brna) RNA_def_property_struct_type(prop, "Object"); RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, "rna_SceneCollection_objects_get", NULL, NULL, NULL, NULL); RNA_def_property_ui_text(prop, "Filter Objects", "All the objects dynamically added to this collection via the filter"); + + /* Functions */ + func = RNA_def_function(srna, "move_above", "rna_SceneCollection_move_above"); + RNA_def_function_ui_description(func, "Move collection after another"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); + parm = RNA_def_pointer(func, "sc_dst", "SceneCollection", "Collection", "Reference collection above which the collection will move"); + parm = RNA_def_boolean(func, "result", false, "Result", "Whether the operation succeded"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "move_below", "rna_SceneCollection_move_below"); + RNA_def_function_ui_description(func, "Move collection before another"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); + parm = RNA_def_pointer(func, "sc_dst", "SceneCollection", "Collection", "Reference collection below which the collection will move"); + parm = RNA_def_boolean(func, "result", false, "Result", "Whether the operation succeded"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "move_into", "rna_SceneCollection_move_into"); + RNA_def_function_ui_description(func, "Move collection into another"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); + parm = RNA_def_pointer(func, "sc_dst", "SceneCollection", "Collection", "Collection to insert into"); + parm = RNA_def_boolean(func, "result", false, "Result", "Whether the operation succeded"); + RNA_def_function_return(func, parm); } static void rna_def_layer_collection_override(BlenderRNA *brna) @@ -6118,6 +6179,7 @@ static void rna_def_layer_collection(BlenderRNA *brna) RNA_def_property_struct_type(prop, "LayerCollectionOverride"); RNA_def_property_ui_text(prop, "Collection Overrides", ""); + /* Functions */ func = RNA_def_function(srna, "get_engine_settings", "rna_LayerCollection_engine_settings_get"); RNA_def_function_ui_description(func, "Return the engine settings for this collection"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_CONTEXT); @@ -6136,6 +6198,27 @@ static void rna_def_layer_collection(BlenderRNA *brna) RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "move_above", "rna_LayerCollection_move_above"); + RNA_def_function_ui_description(func, "Move collection after another"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); + parm = RNA_def_pointer(func, "lc_dst", "LayerCollection", "Collection", "Reference collection above which the collection will move"); + parm = RNA_def_boolean(func, "result", false, "Result", "Whether the operation succeded"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "move_below", "rna_LayerCollection_move_below"); + RNA_def_function_ui_description(func, "Move collection before another"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); + parm = RNA_def_pointer(func, "lc_dst", "LayerCollection", "Collection", "Reference collection below which the collection will move"); + parm = RNA_def_boolean(func, "result", false, "Result", "Whether the operation succeded"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "move_into", "rna_LayerCollection_move_into"); + RNA_def_function_ui_description(func, "Move collection into another"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID); + parm = RNA_def_pointer(func, "lc_dst", "LayerCollection", "Collection", "Collection to insert into"); + parm = RNA_def_boolean(func, "result", false, "Result", "Whether the operation succeded"); + RNA_def_function_return(func, parm); + /* Flags */ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", COLLECTION_VISIBLE); |