Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/space_outliner/outliner_tree.c
| Show First 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | |||||
| #include "outliner_intern.h" | #include "outliner_intern.h" | ||||
| #ifdef WIN32 | #ifdef WIN32 | ||||
| # include "BLI_math_base.h" /* M_PI */ | # include "BLI_math_base.h" /* M_PI */ | ||||
| #endif | #endif | ||||
| /* prototypes */ | /* prototypes */ | ||||
| static void outliner_add_layer_collections_recursive( | static TreeElement *outliner_add_collection_recursive( | ||||
| SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten, | SpaceOops *soops, Collection *collection, TreeElement *ten); | ||||
| const bool show_objects); | |||||
| static TreeElement *outliner_add_scene_collection_recursive( | |||||
| SpaceOops *soops, ListBase *tree, Scene *scene, SceneCollection *scene_collection, TreeElement *parent_ten); | |||||
| static void outliner_add_view_layer( | |||||
| SpaceOops *soops, ListBase *tree, TreeElement *parent, | |||||
| Scene *scene, ViewLayer *layer, const bool show_objects); | |||||
| static void outliner_make_object_parent_hierarchy(ListBase *lb); | static void outliner_make_object_parent_hierarchy(ListBase *lb); | ||||
| /* ********************************************************* */ | /* ********************************************************* */ | ||||
| /* Persistent Data */ | /* Persistent Data */ | ||||
| static void outliner_storage_cleanup(SpaceOops *soops) | static void outliner_storage_cleanup(SpaceOops *soops) | ||||
| { | { | ||||
| BLI_mempool *ts = soops->treestore; | BLI_mempool *ts = soops->treestore; | ||||
| ▲ Show 20 Lines • Show All 178 Lines • ▼ Show 20 Lines | for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| #endif | #endif | ||||
| static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *sce, TreeElement *te) | static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *sce, TreeElement *te) | ||||
| { | { | ||||
| /* View layers */ | /* View layers */ | ||||
| TreeElement *tenla = outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0); | TreeElement *ten = outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0); | ||||
| tenla->name = IFACE_("View Layers"); | ten->name = IFACE_("View Layers"); | ||||
| ViewLayer *view_layer; | ViewLayer *view_layer; | ||||
| for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { | for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { | ||||
| TreeElement *tenlay = outliner_add_element(soops, &tenla->subtree, sce, te, TSE_R_LAYER, 0); | TreeElement *tenlay = outliner_add_element(soops, &ten->subtree, sce, te, TSE_R_LAYER, 0); | ||||
| tenlay->name = view_layer->name; | tenlay->name = view_layer->name; | ||||
| tenlay->directdata = view_layer; | tenlay->directdata = view_layer; | ||||
| } | } | ||||
| /* Collections */ | /* Collections */ | ||||
| outliner_add_scene_collection_recursive(soops, lb, sce, sce->collection, NULL); | ten = outliner_add_element(soops, lb, &sce->id, te, TSE_SCENE_COLLECTION_BASE, 0); | ||||
| ten->name = IFACE_("Collections"); | |||||
| outliner_add_collection_recursive(soops, sce->master_collection, ten); | |||||
| /* Objects */ | /* Objects */ | ||||
| tenla = outliner_add_element(soops, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0); | ten = outliner_add_element(soops, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0); | ||||
| tenla->name = IFACE_("Objects"); | ten->name = IFACE_("Objects"); | ||||
| FOREACH_SCENE_OBJECT_BEGIN(sce, ob) | FOREACH_SCENE_OBJECT_BEGIN(sce, ob) | ||||
| { | { | ||||
| outliner_add_element(soops, &tenla->subtree, ob, NULL, 0, 0); | outliner_add_element(soops, &ten->subtree, ob, NULL, 0, 0); | ||||
| } | } | ||||
| FOREACH_SCENE_OBJECT_END; | FOREACH_SCENE_OBJECT_END; | ||||
| outliner_make_object_parent_hierarchy(&tenla->subtree); | outliner_make_object_parent_hierarchy(&ten->subtree); | ||||
| /* Animation Data */ | /* Animation Data */ | ||||
| if (outliner_animdata_test(sce->adt)) | if (outliner_animdata_test(sce->adt)) | ||||
| outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0); | outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0); | ||||
| /* Grease Pencil */ | /* Grease Pencil */ | ||||
| outliner_add_element(soops, lb, sce->gpd, te, 0, 0); | outliner_add_element(soops, lb, sce->gpd, te, 0, 0); | ||||
| } | } | ||||
| TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata) | TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata) | ||||
| { | { | ||||
| struct ObjectsSelectedData *data = customdata; | struct ObjectsSelectedData *data = customdata; | ||||
| TreeStoreElem *tselem = TREESTORE(te); | TreeStoreElem *tselem = TREESTORE(te); | ||||
| if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) { | if (outliner_is_collection_tree_element(te)) { | ||||
| return TRAVERSE_CONTINUE; | return TRAVERSE_CONTINUE; | ||||
| } | } | ||||
| if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { | if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { | ||||
| return TRAVERSE_SKIP_CHILDS; | return TRAVERSE_SKIP_CHILDS; | ||||
| } | } | ||||
| BLI_addtail(&data->objects_selected_array, BLI_genericNodeN(te)); | BLI_addtail(&data->objects_selected_array, BLI_genericNodeN(te)); | ||||
| return TRAVERSE_CONTINUE; | return TRAVERSE_CONTINUE; | ||||
| } | } | ||||
| /** | /** | ||||
| * Move objects from a collection to another. | * Move objects from a collection to another. | ||||
| * We ignore the original object being inserted, we used it for polling only. | * We ignore the original object being inserted, we used it for polling only. | ||||
| * Instead we move all the selected objects around. | * Instead we move all the selected objects around. | ||||
| */ | */ | ||||
| static void outliner_object_reorder( | static void outliner_object_reorder( | ||||
| Main *bmain, SpaceOops *soops, | Main *bmain, Scene *scene, | ||||
| SpaceOops *soops, | |||||
| TreeElement *insert_element, | TreeElement *insert_element, | ||||
| TreeElement *insert_handle, TreeElementInsertType action, | TreeElement *insert_handle, TreeElementInsertType action, | ||||
| const wmEvent *event) | const wmEvent *event) | ||||
| { | { | ||||
| SceneCollection *sc = outliner_scene_collection_from_tree_element(insert_handle); | Collection *collection = outliner_collection_from_tree_element(insert_handle); | ||||
| SceneCollection *sc_ob_parent = NULL; | Collection *collection_ob_parent = NULL; | ||||
| ID *id = insert_handle->store_elem->id; | ID *id = insert_handle->store_elem->id; | ||||
| BLI_assert(action == TE_INSERT_INTO); | BLI_assert(action == TE_INSERT_INTO); | ||||
| UNUSED_VARS_NDEBUG(action); | UNUSED_VARS_NDEBUG(action); | ||||
| struct ObjectsSelectedData data = { | struct ObjectsSelectedData data = { | ||||
| .objects_selected_array = {NULL, NULL}, | .objects_selected_array = {NULL, NULL}, | ||||
| }; | }; | ||||
| const bool is_append = event->ctrl; | const bool is_append = event->ctrl; | ||||
| /* Make sure we include the originally inserted element as well. */ | /* Make sure we include the originally inserted element as well. */ | ||||
| TREESTORE(insert_element)->flag |= TSE_SELECTED; | TREESTORE(insert_element)->flag |= TSE_SELECTED; | ||||
| outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data); | outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data); | ||||
| LISTBASE_FOREACH (LinkData *, link, &data.objects_selected_array) { | LISTBASE_FOREACH (LinkData *, link, &data.objects_selected_array) { | ||||
| TreeElement *ten_selected = (TreeElement *)link->data; | TreeElement *ten_selected = (TreeElement *)link->data; | ||||
| Object *ob = (Object *)TREESTORE(ten_selected)->id; | Object *ob = (Object *)TREESTORE(ten_selected)->id; | ||||
| if (is_append) { | if (is_append) { | ||||
| BKE_collection_object_add(id, sc, ob); | BKE_collection_object_add(bmain, collection, ob); | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* Find parent scene-collection of object. */ | /* Find parent collection of object. */ | ||||
| if (ten_selected->parent) { | if (ten_selected->parent) { | ||||
| for (TreeElement *te_ob_parent = ten_selected->parent; te_ob_parent; te_ob_parent = te_ob_parent->parent) { | for (TreeElement *te_ob_parent = ten_selected->parent; te_ob_parent; te_ob_parent = te_ob_parent->parent) { | ||||
| if (ELEM(TREESTORE(te_ob_parent)->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION)) { | if (outliner_is_collection_tree_element(te_ob_parent)) { | ||||
| sc_ob_parent = outliner_scene_collection_from_tree_element(te_ob_parent); | collection_ob_parent = outliner_collection_from_tree_element(te_ob_parent); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| sc_ob_parent = BKE_collection_master(id); | collection_ob_parent = BKE_collection_master(scene); | ||||
| } | } | ||||
| BKE_collection_object_move(id, sc, sc_ob_parent, ob); | BKE_collection_object_move(bmain, scene, collection, collection_ob_parent, ob); | ||||
| } | } | ||||
| BLI_freelistN(&data.objects_selected_array); | BLI_freelistN(&data.objects_selected_array); | ||||
| DEG_relations_tag_update(bmain); | DEG_relations_tag_update(bmain); | ||||
| /* TODO(sergey): Use proper flag for tagging here. */ | /* TODO(sergey): Use proper flag for tagging here. */ | ||||
| DEG_id_tag_update(id, 0); | DEG_id_tag_update(id, 0); | ||||
| WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); | WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); | ||||
| } | } | ||||
| static bool outliner_object_reorder_poll( | static bool outliner_object_reorder_poll( | ||||
| const TreeElement *insert_element, | const TreeElement *insert_element, | ||||
| TreeElement **io_insert_handle, TreeElementInsertType *io_action) | TreeElement **io_insert_handle, TreeElementInsertType *io_action) | ||||
| { | { | ||||
| TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle); | if (outliner_is_collection_tree_element(*io_insert_handle) && | ||||
| if (ELEM(tselem_handle->type, TSE_SCENE_COLLECTION, TSE_LAYER_COLLECTION) && | |||||
| (insert_element->parent != *io_insert_handle)) | (insert_element->parent != *io_insert_handle)) | ||||
| { | { | ||||
| *io_action = TE_INSERT_INTO; | *io_action = TE_INSERT_INTO; | ||||
| return true; | return true; | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 388 Lines • ▼ Show 20 Lines | case ID_GD: | ||||
| // TODO: base element for layers? | // TODO: base element for layers? | ||||
| for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { | for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { | ||||
| outliner_add_element(soops, &te->subtree, gpl, te, TSE_GP_LAYER, a); | outliner_add_element(soops, &te->subtree, gpl, te, TSE_GP_LAYER, a); | ||||
| a++; | a++; | ||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| case ID_GR: | |||||
| { | |||||
| Collection *collection = (Collection *)id; | |||||
| outliner_add_collection_recursive(soops, collection, te); | |||||
| } | |||||
| default: | default: | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| // TODO: this function needs to be split up! It's getting a bit too large... | // TODO: this function needs to be split up! It's getting a bit too large... | ||||
| // Note: "ID" is not always a real ID | // Note: "ID" is not always a real ID | ||||
| static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv, | static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *idv, | ||||
| ▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { | ||||
| /* pass */ | /* pass */ | ||||
| } | } | ||||
| else if (type == TSE_ANIM_DATA) { | else if (type == TSE_ANIM_DATA) { | ||||
| /* pass */ | /* pass */ | ||||
| } | } | ||||
| else if (type == TSE_GP_LAYER) { | else if (type == TSE_GP_LAYER) { | ||||
| /* pass */ | /* pass */ | ||||
| } | } | ||||
| else if (ELEM(type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) { | else if (ELEM(type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION_BASE)) { | ||||
| /* pass */ | /* pass */ | ||||
| } | } | ||||
| else if (type == TSE_ID_BASE) { | else if (type == TSE_ID_BASE) { | ||||
| /* pass */ | /* pass */ | ||||
| } | } | ||||
| else { | else { | ||||
| /* do here too, for blend file viewer, own ID_LI then shows file name */ | /* do here too, for blend file viewer, own ID_LI then shows file name */ | ||||
| if (GS(id->name) == ID_LI) | if (GS(id->name) == ID_LI) | ||||
| ▲ Show 20 Lines • Show All 284 Lines • ▼ Show 20 Lines | if (TSELEM_OPEN(tselem, soops)) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| else | else | ||||
| te->flag |= TE_LAZY_CLOSED; | te->flag |= TE_LAZY_CLOSED; | ||||
| } | } | ||||
| if ((type != TSE_LAYER_COLLECTION) && (te->idcode == ID_GR)) { | |||||
| Group *group = (Group *)id; | |||||
| outliner_add_layer_collections_recursive(soops, &te->subtree, id, &group->view_layer->layer_collections, NULL, true); | |||||
| } | |||||
| return te; | return te; | ||||
| } | } | ||||
| /** | /** | ||||
| * \note Really only removes \a tselem, not it's TreeElement instance or any children. | * \note Really only removes \a tselem, not it's TreeElement instance or any children. | ||||
| */ | */ | ||||
| void outliner_remove_treestore_element(SpaceOops *soops, TreeStoreElem *tselem) | void outliner_remove_treestore_element(SpaceOops *soops, TreeStoreElem *tselem) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 133 Lines • ▼ Show 20 Lines | if (lbarray[a]->first) { | ||||
| if (ID_REAL_USERS(id) <= 0) | if (ID_REAL_USERS(id) <= 0) | ||||
| outliner_add_element(soops, &ten->subtree, id, ten, 0, 0); | outliner_add_element(soops, &ten->subtree, id, ten, 0, 0); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void outliner_layer_collections_reorder( | static void outliner_collections_reorder( | ||||
| Main *bmain, | Main *bmain, | ||||
| SpaceOops *UNUSED(soops), | Scene *UNUSED(scene), | ||||
| TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action, | SpaceOops *soops, | ||||
| TreeElement *insert_element, | |||||
| TreeElement *insert_handle, | |||||
| TreeElementInsertType action, | |||||
| const wmEvent *UNUSED(event)) | const wmEvent *UNUSED(event)) | ||||
| { | { | ||||
| LayerCollection *lc_insert = insert_element->directdata; | TreeElement *from_parent_te, *to_parent_te; | ||||
| LayerCollection *lc_handle = insert_handle->directdata; | Collection *from_parent, *to_parent; | ||||
| ID *id = insert_element->store_elem->id; | |||||
| if (action == TE_INSERT_BEFORE) { | Collection *collection = outliner_collection_from_tree_element(insert_element); | ||||
| BKE_layer_collection_move_above(id, lc_handle, lc_insert); | Collection *relative = NULL; | ||||
| } | bool relative_after = false; | ||||
| else if (action == TE_INSERT_AFTER) { | |||||
| BKE_layer_collection_move_below(id, lc_handle, lc_insert); | from_parent_te = outliner_find_parent_element(&soops->tree, NULL, insert_element); | ||||
| from_parent = (from_parent_te) ? outliner_collection_from_tree_element(from_parent_te) : NULL; | |||||
| if (ELEM(action, TE_INSERT_BEFORE, TE_INSERT_AFTER)) { | |||||
| to_parent_te = outliner_find_parent_element(&soops->tree, NULL, insert_handle); | |||||
| to_parent = (to_parent_te) ? outliner_collection_from_tree_element(to_parent_te) : NULL; | |||||
| relative = outliner_collection_from_tree_element(insert_handle); | |||||
| relative_after = (action == TE_INSERT_AFTER); | |||||
| } | } | ||||
| else if (action == TE_INSERT_INTO) { | else if (action == TE_INSERT_INTO) { | ||||
| BKE_layer_collection_move_into(id, lc_handle, lc_insert); | to_parent = outliner_collection_from_tree_element(insert_handle); | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_assert(0); | BLI_assert(0); | ||||
| return; | |||||
| } | } | ||||
| if (!to_parent) { | |||||
| return; | |||||
| } | |||||
| BKE_collection_move(bmain, to_parent, from_parent, relative, relative_after, collection); | |||||
| DEG_relations_tag_update(bmain); | DEG_relations_tag_update(bmain); | ||||
| } | } | ||||
| static bool outliner_layer_collections_reorder_poll( | |||||
| static bool outliner_collections_reorder_poll( | |||||
| const TreeElement *insert_element, | const TreeElement *insert_element, | ||||
| TreeElement **io_insert_handle, TreeElementInsertType *UNUSED(io_action)) | TreeElement **io_insert_handle, | ||||
| TreeElementInsertType *io_action) | |||||
| { | { | ||||
| const TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle); | /* Can't move master collection. */ | ||||
| Collection *collection = outliner_collection_from_tree_element(insert_element); | |||||
| if (tselem_handle->id != insert_element->store_elem->id) { | if (collection->flag & COLLECTION_IS_MASTER) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| return ELEM(tselem_handle->type, TSE_LAYER_COLLECTION); | /* Can only move into collections. */ | ||||
| Collection *collection_handle = outliner_collection_from_tree_element(*io_insert_handle); | |||||
| if (collection_handle == NULL) { | |||||
| return false; | |||||
| } | } | ||||
| static void outliner_add_layer_collections_recursive( | /* We can't insert/before after master collection. */ | ||||
| SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten, | if (collection_handle->flag & COLLECTION_IS_MASTER) { | ||||
| const bool show_objects) | if (*io_action == TE_INSERT_BEFORE) { | ||||
| { | /* can't go higher than master collection, insert into it */ | ||||
| for (LayerCollection *collection = layer_collections->first; collection; collection = collection->next) { | *io_action = TE_INSERT_INTO; | ||||
| TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_LAYER_COLLECTION, 0); | |||||
| ten->name = collection->scene_collection->name; | |||||
| ten->directdata = collection; | |||||
| ten->reinsert = outliner_layer_collections_reorder; | |||||
| ten->reinsert_poll = outliner_layer_collections_reorder_poll; | |||||
| outliner_add_layer_collections_recursive(soops, &ten->subtree, id, &collection->layer_collections, ten, show_objects); | |||||
| if (show_objects) { | |||||
| for (LinkData *link = collection->object_bases.first; link; link = link->next) { | |||||
| Base *base = (Base *)link->data; | |||||
| TreeElement *te_object = outliner_add_element(soops, &ten->subtree, base->object, ten, 0, 0); | |||||
| te_object->directdata = base; | |||||
| } | |||||
| } | } | ||||
| else if (*io_action == TE_INSERT_AFTER) { | |||||
| *io_insert_handle = (*io_insert_handle)->subtree.last; | |||||
| } | } | ||||
| } | } | ||||
| static void outliner_add_view_layer(SpaceOops *soops, ListBase *tree, TreeElement *parent, | return true; | ||||
| Scene *scene, ViewLayer *layer, const bool show_objects) | |||||
| { | |||||
| outliner_add_layer_collections_recursive(soops, tree, &scene->id, &layer->layer_collections, parent, show_objects); | |||||
| } | } | ||||
| static void outliner_scene_collections_reorder( | static void outliner_add_layer_collection_objects( | ||||
| Main *bmain, | SpaceOops *soops, ListBase *tree, ViewLayer *layer, | ||||
| SpaceOops *UNUSED(soops), | LayerCollection *lc, TreeElement *ten) | ||||
| TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action, | { | ||||
| const wmEvent *UNUSED(event)) | for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) { | ||||
| { | Base *base = BKE_view_layer_base_find(layer, cob->ob); | ||||
| SceneCollection *sc_insert = insert_element->directdata; | TreeElement *te_object = outliner_add_element(soops, tree, base->object, ten, 0, 0); | ||||
| SceneCollection *sc_handle = insert_handle->directdata; | te_object->directdata = base; | ||||
| ID *id = insert_handle->store_elem->id; | |||||
| BLI_assert(id == insert_element->store_elem->id); | |||||
| BLI_assert((action == TE_INSERT_INTO) || (sc_handle != BKE_collection_master(id))); | |||||
| if (action == TE_INSERT_BEFORE) { | |||||
| BKE_collection_move_above(id, sc_handle, sc_insert); | |||||
| } | } | ||||
| else if (action == TE_INSERT_AFTER) { | |||||
| BKE_collection_move_below(id, sc_handle, sc_insert); | |||||
| } | } | ||||
| else if (action == TE_INSERT_INTO) { | |||||
| BKE_collection_move_into(id, sc_handle, sc_insert); | static bool outliner_layer_collection_is_visible(LayerCollection *lc) | ||||
| } | { | ||||
| else { | if (!(lc->flag & LAYER_COLLECTION_EXCLUDE)) { | ||||
| BLI_assert(0); | return true; | ||||
| } | } | ||||
| DEG_relations_tag_update(bmain); | for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { | ||||
| if (outliner_layer_collection_is_visible(nlc)) { | |||||
| return true; | |||||
| } | |||||
| } | } | ||||
| static bool outliner_scene_collections_reorder_poll( | |||||
| const TreeElement *insert_element, | |||||
| TreeElement **io_insert_handle, TreeElementInsertType *io_action) | |||||
| { | |||||
| const TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle); | |||||
| ID *id = tselem_handle->id; | |||||
| if (id != insert_element->store_elem->id) { | |||||
| return false; | return false; | ||||
| } | } | ||||
| if (!ELEM(tselem_handle->type, TSE_SCENE_COLLECTION)) { | static void outliner_add_layer_collections_recursive( | ||||
| return false; | SpaceOops *soops, ListBase *tree, ViewLayer *layer, | ||||
| ListBase *layer_collections, TreeElement *parent_ten, | |||||
| const bool show_objects) | |||||
| { | |||||
| for (LayerCollection *lc = layer_collections->first; lc; lc = lc->next) { | |||||
| if ((soops->outlinevis != SO_VIEW_LAYER) && | |||||
| !outliner_layer_collection_is_visible(lc)) | |||||
| { | |||||
| continue; | |||||
| } | } | ||||
| SceneCollection *sc_master = BKE_collection_master(id); | ID *id = &lc->collection->id; | ||||
| SceneCollection *sc_handle = (*io_insert_handle)->directdata; | TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_LAYER_COLLECTION, 0); | ||||
| if (sc_handle == sc_master) { | ten->name = id->name + 2; | ||||
| /* exception: Can't insert before/after master selection, has to be one of its childs */ | ten->directdata = lc; | ||||
| TreeElement *te_master = *io_insert_handle; | ten->reinsert = outliner_collections_reorder; | ||||
| if (*io_action == TE_INSERT_BEFORE) { | ten->reinsert_poll = outliner_collections_reorder_poll; | ||||
| /* can't go higher than master collection, insert into it */ | |||||
| *io_action = TE_INSERT_INTO; | const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0; | ||||
| if (exclude) { | |||||
| ten->flag |= TE_DISABLED; | |||||
| } | } | ||||
| else if (*io_action == TE_INSERT_AFTER) { | |||||
| *io_insert_handle = te_master->subtree.last; | outliner_add_layer_collections_recursive(soops, &ten->subtree, layer, &lc->layer_collections, ten, show_objects); | ||||
| if (!exclude && show_objects) { | |||||
| outliner_add_layer_collection_objects(soops, &ten->subtree, layer, lc, ten); | |||||
| } | } | ||||
| } | } | ||||
| return true; | |||||
| } | } | ||||
| BLI_INLINE void outliner_add_scene_collection_init(TreeElement *te, Scene *scene, SceneCollection *collection) | static void outliner_add_view_layer(SpaceOops *soops, ListBase *tree, TreeElement *parent, | ||||
| ViewLayer *layer, const bool show_objects) | |||||
| { | |||||
| /* First layer collection is for master collection, don't show it. */ | |||||
| LayerCollection *lc = layer->layer_collections.first; | |||||
| if (lc == NULL) { | |||||
| return; | |||||
| } | |||||
| outliner_add_layer_collections_recursive(soops, tree, layer, &lc->layer_collections, parent, show_objects); | |||||
| if (show_objects) { | |||||
| outliner_add_layer_collection_objects(soops, tree, layer, lc, parent); | |||||
| } | |||||
| } | |||||
| BLI_INLINE void outliner_add_collection_init(TreeElement *te, Collection *collection) | |||||
| { | { | ||||
| if (collection == scene->collection) { | if (collection->flag & COLLECTION_IS_MASTER) { | ||||
| // Don't display name of master collection | |||||
| te->name = IFACE_("Collections"); | te->name = IFACE_("Collections"); | ||||
| } | } | ||||
| else { | else { | ||||
| te->name = collection->name; | te->name = collection->id.name + 2; | ||||
| } | } | ||||
| te->directdata = collection; | te->directdata = collection; | ||||
| te->reinsert = outliner_scene_collections_reorder; | te->reinsert = outliner_collections_reorder; | ||||
| te->reinsert_poll = outliner_scene_collections_reorder_poll; | te->reinsert_poll = outliner_collections_reorder_poll; | ||||
| } | } | ||||
| BLI_INLINE void outliner_add_scene_collection_objects( | BLI_INLINE void outliner_add_collection_objects( | ||||
| SpaceOops *soops, ListBase *tree, SceneCollection *collection, TreeElement *parent) | SpaceOops *soops, ListBase *tree, Collection *collection, TreeElement *parent) | ||||
| { | { | ||||
| for (LinkData *link = collection->objects.first; link; link = link->next) { | for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { | ||||
| outliner_add_element(soops, tree, link->data, parent, 0, 0); | outliner_add_element(soops, tree, cob->ob, parent, 0, 0); | ||||
| } | } | ||||
| } | } | ||||
| static TreeElement *outliner_add_scene_collection_recursive( | static TreeElement *outliner_add_collection_recursive( | ||||
| SpaceOops *soops, ListBase *tree, Scene *scene, SceneCollection *scene_collection, TreeElement *parent_ten) | SpaceOops *soops, Collection *collection, TreeElement *ten) | ||||
| { | { | ||||
| TreeElement *ten = outliner_add_element(soops, tree, &scene->id, parent_ten, TSE_SCENE_COLLECTION, 0); | outliner_add_collection_init(ten, collection); | ||||
| outliner_add_scene_collection_init(ten, scene, scene_collection); | |||||
| if (soops->outlinevis != SO_SCENES) { | for (CollectionChild *child = collection->children.first; child; child = child->next) { | ||||
| outliner_add_scene_collection_objects(soops, &ten->subtree, scene_collection, ten); | outliner_add_element(soops, &ten->subtree, &child->collection->id, ten, 0, 0); | ||||
| } | } | ||||
| for (SceneCollection *scene_collection_nested = scene_collection->scene_collections.first; | if (soops->outlinevis != SO_SCENES) { | ||||
| scene_collection_nested != NULL; | outliner_add_collection_objects(soops, &ten->subtree, collection, ten); | ||||
| scene_collection_nested = scene_collection_nested->next) | |||||
| { | |||||
| outliner_add_scene_collection_recursive(soops, &ten->subtree, scene, scene_collection_nested, ten); | |||||
| } | } | ||||
| return ten; | return ten; | ||||
| } | } | ||||
| /* ======================================================= */ | /* ======================================================= */ | ||||
| /* Generic Tree Building helpers - order these are called is top to bottom */ | /* Generic Tree Building helpers - order these are called is top to bottom */ | ||||
| ▲ Show 20 Lines • Show All 199 Lines • ▼ Show 20 Lines | if (focus->tselem != NULL) { | ||||
| else { | else { | ||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static bool test_collection_callback(TreeElement *te) | static bool test_collection_callback(TreeElement *te) | ||||
| { | { | ||||
| TreeStoreElem *tselem = TREESTORE(te); | return outliner_is_collection_tree_element(te); | ||||
| return ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION); | |||||
| } | } | ||||
| static bool test_object_callback(TreeElement *te) | static bool test_object_callback(TreeElement *te) | ||||
| { | { | ||||
| TreeStoreElem *tselem = TREESTORE(te); | TreeStoreElem *tselem = TREESTORE(te); | ||||
| return ((tselem->type == 0) && (te->idcode == ID_OB)); | return ((tselem->type == 0) && (te->idcode == ID_OB)); | ||||
| } | } | ||||
| Show All 37 Lines | static TreeElement *outliner_find_first_desired_element_at_y( | ||||
| const SpaceOops *soops, | const SpaceOops *soops, | ||||
| const float view_co, | const float view_co, | ||||
| const float view_co_limit) | const float view_co_limit) | ||||
| { | { | ||||
| TreeElement *te, *te_sub; | TreeElement *te, *te_sub; | ||||
| te = outliner_find_item_at_y(soops, &soops->tree, view_co); | te = outliner_find_item_at_y(soops, &soops->tree, view_co); | ||||
| bool (*callback_test)(TreeElement *); | bool (*callback_test)(TreeElement *); | ||||
| if (soops->filter & SO_FILTER_NO_COLLECTION) { | if (soops->outlinevis == SO_OBJECTS) { | ||||
| callback_test = test_object_callback; | callback_test = test_object_callback; | ||||
| } | } | ||||
| else { | else { | ||||
| callback_test = test_collection_callback; | callback_test = test_collection_callback; | ||||
| } | } | ||||
| while (te != NULL) { | while (te != NULL) { | ||||
| te_sub = outliner_find_first_desired_element_at_y_recursive(soops, te, view_co_limit, callback_test); | te_sub = outliner_find_first_desired_element_at_y_recursive(soops, te, view_co_limit, callback_test); | ||||
| ▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | if (soops->filter & SO_FILTER_SEARCH) { | ||||
| } | } | ||||
| } | } | ||||
| /* Let's have this for the collection options at first. */ | /* Let's have this for the collection options at first. */ | ||||
| if (!SUPPORT_FILTER_OUTLINER(soops)) { | if (!SUPPORT_FILTER_OUTLINER(soops)) { | ||||
| return (exclude_filter & SO_FILTER_SEARCH); | return (exclude_filter & SO_FILTER_SEARCH); | ||||
| } | } | ||||
| switch (soops->filter_state) { | if (soops->outlinevis == SO_COLLECTIONS && (soops->filter & SO_FILTER_NO_OBJECT)) { | ||||
| case SO_FILTER_OB_NONE: | |||||
| exclude_filter |= SO_FILTER_OB_TYPE; | exclude_filter |= SO_FILTER_OB_TYPE; | ||||
| break; | } | ||||
| switch (soops->filter_state) { | |||||
| case SO_FILTER_OB_VISIBLE: | case SO_FILTER_OB_VISIBLE: | ||||
| exclude_filter |= SO_FILTER_OB_STATE_VISIBLE; | exclude_filter |= SO_FILTER_OB_STATE_VISIBLE; | ||||
| break; | break; | ||||
| case SO_FILTER_OB_SELECTED: | case SO_FILTER_OB_SELECTED: | ||||
| exclude_filter |= SO_FILTER_OB_STATE_SELECTED; | exclude_filter |= SO_FILTER_OB_STATE_SELECTED; | ||||
| break; | break; | ||||
| case SO_FILTER_OB_ACTIVE: | case SO_FILTER_OB_ACTIVE: | ||||
| exclude_filter |= SO_FILTER_OB_STATE_ACTIVE; | exclude_filter |= SO_FILTER_OB_STATE_ACTIVE; | ||||
| ▲ Show 20 Lines • Show All 277 Lines • ▼ Show 20 Lines | for (sce = mainvar->scene.first; sce; sce = sce->id.next) { | ||||
| if (sce == scene && show_opened) { | if (sce == scene && show_opened) { | ||||
| tselem->flag &= ~TSE_CLOSED; | tselem->flag &= ~TSE_CLOSED; | ||||
| } | } | ||||
| outliner_make_object_parent_hierarchy(&te->subtree); | outliner_make_object_parent_hierarchy(&te->subtree); | ||||
| } | } | ||||
| } | } | ||||
| else if (soops->outlinevis == SO_GROUPS) { | |||||
| Group *group; | |||||
| for (group = mainvar->group.first; group; group = group->id.next) { | |||||
| te = outliner_add_element(soops, &soops->tree, group, NULL, 0, 0); | |||||
| } | |||||
| } | |||||
| else if (soops->outlinevis == SO_SEQUENCE) { | else if (soops->outlinevis == SO_SEQUENCE) { | ||||
| Sequence *seq; | Sequence *seq; | ||||
| Editing *ed = BKE_sequencer_editing_get(scene, false); | Editing *ed = BKE_sequencer_editing_get(scene, false); | ||||
| int op; | int op; | ||||
| if (ed == NULL) | if (ed == NULL) | ||||
| return; | return; | ||||
| Show All 23 Lines | else if (soops->outlinevis == SO_DATABLOCKS) { | ||||
| if (show_opened) { | if (show_opened) { | ||||
| tselem = TREESTORE(ten); | tselem = TREESTORE(ten); | ||||
| tselem->flag &= ~TSE_CLOSED; | tselem->flag &= ~TSE_CLOSED; | ||||
| } | } | ||||
| } | } | ||||
| else if (soops->outlinevis == SO_ID_ORPHANS) { | else if (soops->outlinevis == SO_ID_ORPHANS) { | ||||
| outliner_add_orphaned_datablocks(mainvar, soops); | outliner_add_orphaned_datablocks(mainvar, soops); | ||||
| } | } | ||||
| else if (soops->outlinevis == SO_COLLECTIONS) { | else if (soops->outlinevis == SO_COLLECTIONS && | ||||
| soops->filter_collection != SO_FILTER_COLLECTION_SCENE) { | |||||
| Collection *collection; | |||||
| for (collection = mainvar->collection.first; collection; collection = collection->id.next) { | |||||
| if (soops->filter_collection == SO_FILTER_COLLECTION_UNLINKED) { | |||||
| /* Skip collections used in a scene */ | |||||
| if (BKE_collection_is_in_scene(collection)) { | |||||
| continue; | |||||
| } | |||||
| } | |||||
| if (collection->parents.first) { | |||||
| /* Don't show child collections of non-scene master collection, | |||||
| * they are already shown as children. */ | |||||
| bool has_non_scene_parent = false; | |||||
| for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) { | |||||
| if (!(cparent->collection->flag & COLLECTION_IS_MASTER)) { | |||||
| has_non_scene_parent = true; | |||||
| } | |||||
| } | |||||
| if (has_non_scene_parent) { | |||||
| continue; | |||||
| } | |||||
| } | |||||
| te = outliner_add_element(soops, &soops->tree, collection, NULL, 0, 0); | |||||
| } | |||||
| } | |||||
| else if (ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_COLLECTIONS)) { | |||||
| /* Show collections and objects in the view layer. */ | |||||
| TreeElement *tenlay = outliner_add_element(soops, &soops->tree, scene, te, TSE_R_LAYER, 0); | |||||
| tenlay->name = view_layer->name; | |||||
| tenlay->directdata = view_layer; | |||||
| TREESTORE(tenlay)->flag &= ~TSE_CLOSED; | |||||
| bool show_objects = (soops->outlinevis == SO_COLLECTIONS) && | |||||
| !(soops->filter & SO_FILTER_NO_OBJECT); | |||||
| outliner_add_view_layer(soops, &tenlay->subtree, tenlay, view_layer, show_objects); | |||||
| } | |||||
| else { /* SO_OBJECTS */ | |||||
| /* Show objects in the view layer. */ | |||||
| TreeElement *tenlay = outliner_add_element(soops, &soops->tree, scene, te, TSE_R_LAYER, 0); | TreeElement *tenlay = outliner_add_element(soops, &soops->tree, scene, te, TSE_R_LAYER, 0); | ||||
| tenlay->name = view_layer->name; | tenlay->name = view_layer->name; | ||||
| tenlay->directdata = view_layer; | tenlay->directdata = view_layer; | ||||
| TREESTORE(tenlay)->flag &= ~TSE_CLOSED; | TREESTORE(tenlay)->flag &= ~TSE_CLOSED; | ||||
| if (soops->filter & SO_FILTER_NO_COLLECTION) { | |||||
| for (Base *base = view_layer->object_bases.first; base; base = base->next) { | for (Base *base = view_layer->object_bases.first; base; base = base->next) { | ||||
| TreeElement *te_object = outliner_add_element(soops, &tenlay->subtree, base->object, NULL, 0, 0); | TreeElement *te_object = outliner_add_element(soops, &tenlay->subtree, base->object, NULL, 0, 0); | ||||
| te_object->directdata = base; | te_object->directdata = base; | ||||
| } | } | ||||
| outliner_make_object_parent_hierarchy(&tenlay->subtree); | outliner_make_object_parent_hierarchy(&tenlay->subtree); | ||||
| } | } | ||||
| else { | |||||
| outliner_add_view_layer(soops, &tenlay->subtree, NULL, scene, view_layer, true); | |||||
| } | |||||
| } | |||||
| else { | |||||
| if (BASACT(view_layer)) { | |||||
| ten = outliner_add_element(soops, &soops->tree, OBACT(view_layer), NULL, 0, 0); | |||||
| ten->directdata = BASACT(view_layer); | |||||
| } | |||||
| } | |||||
| if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) { | if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) { | ||||
| outliner_sort(&soops->tree); | outliner_sort(&soops->tree); | ||||
| } | } | ||||
| outliner_filter_tree(soops, view_layer); | outliner_filter_tree(soops, view_layer); | ||||
| outliner_restore_scrolling_position(soops, ar, &focus); | outliner_restore_scrolling_position(soops, ar, &focus); | ||||
| BKE_main_id_clear_newpoins(mainvar); | BKE_main_id_clear_newpoins(mainvar); | ||||
| } | } | ||||