diff options
Diffstat (limited to 'source/blender/blenkernel')
-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 |
4 files changed, 247 insertions, 13 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; } - /* ---------------------------------------------------------------------- */ /** |