diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/editors/space_outliner | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/editors/space_outliner')
-rw-r--r-- | source/blender/editors/space_outliner/CMakeLists.txt | 56 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_collections.c | 1829 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_dragdrop.c | 1653 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_draw.c | 4573 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_edit.c | 2931 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_intern.h | 317 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_ops.c | 146 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_select.c | 2215 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_tools.c | 3519 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_tree.c | 3698 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_utils.c | 323 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/space_outliner.c | 598 |
12 files changed, 11414 insertions, 10444 deletions
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index 83832d62b9e..f08069c418b 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -16,47 +16,47 @@ # ***** END GPL LICENSE BLOCK ***** set(INC - ../include - ../../blenkernel - ../../blenlib - ../../blentranslation - ../../depsgraph - ../../imbuf - ../../gpu - ../../makesdna - ../../makesrna - ../../windowmanager - ../../../../intern/guardedalloc - ../../../../intern/glew-mx + ../include + ../../blenkernel + ../../blenlib + ../../blentranslation + ../../depsgraph + ../../imbuf + ../../gpu + ../../makesdna + ../../makesrna + ../../windowmanager + ../../../../intern/guardedalloc + ../../../../intern/glew-mx ) set(INC_SYS - ${GLEW_INCLUDE_PATH} + ${GLEW_INCLUDE_PATH} ) set(SRC - outliner_collections.c - outliner_dragdrop.c - outliner_draw.c - outliner_edit.c - outliner_ops.c - outliner_select.c - outliner_tools.c - outliner_tree.c - outliner_utils.c - space_outliner.c + outliner_collections.c + outliner_dragdrop.c + outliner_draw.c + outliner_edit.c + outliner_ops.c + outliner_select.c + outliner_tools.c + outliner_tree.c + outliner_utils.c + space_outliner.c - outliner_intern.h + outliner_intern.h ) set(LIB - bf_blenkernel - bf_blenlib - bf_editor_undo + bf_blenkernel + bf_blenlib + bf_editor_undo ) if(WITH_INTERNATIONAL) - add_definitions(-DWITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) endif() add_definitions(${GL_DEFINITIONS}) diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index 30eaefe6149..835c154786b 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -56,78 +56,81 @@ bool outliner_is_collection_tree_element(const TreeElement *te) { - TreeStoreElem *tselem = TREESTORE(te); + TreeStoreElem *tselem = TREESTORE(te); - if (!tselem) { - return false; - } + if (!tselem) { + return false; + } - if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { - return true; - } - else if (tselem->type == 0 && te->idcode == ID_GR) { - return true; - } + if (ELEM(tselem->type, + TSE_LAYER_COLLECTION, + TSE_SCENE_COLLECTION_BASE, + TSE_VIEW_COLLECTION_BASE)) { + return true; + } + else if (tselem->type == 0 && te->idcode == ID_GR) { + return true; + } - return false; + return false; } Collection *outliner_collection_from_tree_element(const TreeElement *te) { - TreeStoreElem *tselem = TREESTORE(te); + TreeStoreElem *tselem = TREESTORE(te); - if (!tselem) { - return NULL; - } + if (!tselem) { + return NULL; + } - if (tselem->type == TSE_LAYER_COLLECTION) { - LayerCollection *lc = te->directdata; - return lc->collection; - } - else if (ELEM(tselem->type, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { - Scene *scene = (Scene *)tselem->id; - return BKE_collection_master(scene); - } - else if (tselem->type == 0 && te->idcode == ID_GR) { - return (Collection *)tselem->id; - } + if (tselem->type == TSE_LAYER_COLLECTION) { + LayerCollection *lc = te->directdata; + return lc->collection; + } + else if (ELEM(tselem->type, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { + Scene *scene = (Scene *)tselem->id; + return BKE_collection_master(scene); + } + else if (tselem->type == 0 && te->idcode == ID_GR) { + return (Collection *)tselem->id; + } - return NULL; + return NULL; } TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *customdata) { - struct IDsSelectedData *data = customdata; - TreeStoreElem *tselem = TREESTORE(te); + struct IDsSelectedData *data = customdata; + TreeStoreElem *tselem = TREESTORE(te); - if (outliner_is_collection_tree_element(te)) { - BLI_addtail(&data->selected_array, BLI_genericNodeN(te)); - return TRAVERSE_CONTINUE; - } + if (outliner_is_collection_tree_element(te)) { + BLI_addtail(&data->selected_array, BLI_genericNodeN(te)); + return TRAVERSE_CONTINUE; + } - if (tselem->type || (tselem->id && GS(tselem->id->name) != ID_GR)) { - return TRAVERSE_SKIP_CHILDS; - } + if (tselem->type || (tselem->id && GS(tselem->id->name) != ID_GR)) { + return TRAVERSE_SKIP_CHILDS; + } - return TRAVERSE_CONTINUE; + return TRAVERSE_CONTINUE; } TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata) { - struct IDsSelectedData *data = customdata; - TreeStoreElem *tselem = TREESTORE(te); + struct IDsSelectedData *data = customdata; + TreeStoreElem *tselem = TREESTORE(te); - if (outliner_is_collection_tree_element(te)) { - return TRAVERSE_CONTINUE; - } + if (outliner_is_collection_tree_element(te)) { + return TRAVERSE_CONTINUE; + } - if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { - return TRAVERSE_SKIP_CHILDS; - } + if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { + return TRAVERSE_SKIP_CHILDS; + } - BLI_addtail(&data->selected_array, BLI_genericNodeN(te)); + BLI_addtail(&data->selected_array, BLI_genericNodeN(te)); - return TRAVERSE_CONTINUE; + return TRAVERSE_CONTINUE; } /* -------------------------------------------------------------------- */ @@ -135,1247 +138,1302 @@ TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *custom bool ED_outliner_collections_editor_poll(bContext *C) { - SpaceOutliner *so = CTX_wm_space_outliner(C); - return (so != NULL) && ELEM(so->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_LIBRARIES); + SpaceOutliner *so = CTX_wm_space_outliner(C); + return (so != NULL) && ELEM(so->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_LIBRARIES); } static bool outliner_view_layer_collections_editor_poll(bContext *C) { - SpaceOutliner *so = CTX_wm_space_outliner(C); - return (so != NULL) && (so->outlinevis == SO_VIEW_LAYER); + SpaceOutliner *so = CTX_wm_space_outliner(C); + return (so != NULL) && (so->outlinevis == SO_VIEW_LAYER); } /********************************* New Collection ****************************/ -struct CollectionNewData -{ - bool error; - Collection *collection; +struct CollectionNewData { + bool error; + Collection *collection; }; static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata) { - struct CollectionNewData *data = customdata; - Collection *collection = outliner_collection_from_tree_element(te); + struct CollectionNewData *data = customdata; + Collection *collection = outliner_collection_from_tree_element(te); - if (!collection) { - return TRAVERSE_SKIP_CHILDS; - } + if (!collection) { + return TRAVERSE_SKIP_CHILDS; + } - if (data->collection != NULL) { - data->error = true; - return TRAVERSE_BREAK; - } + if (data->collection != NULL) { + data->error = true; + return TRAVERSE_BREAK; + } - data->collection = collection; - return TRAVERSE_CONTINUE; + data->collection = collection; + return TRAVERSE_CONTINUE; } static int collection_new_exec(bContext *C, wmOperator *op) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - ARegion *ar = CTX_wm_region(C); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + ARegion *ar = CTX_wm_region(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); - struct CollectionNewData data = { - .error = false, - .collection = NULL, - }; + struct CollectionNewData data = { + .error = false, + .collection = NULL, + }; - if (RNA_boolean_get(op->ptr, "nested")) { - outliner_build_tree(bmain, scene, view_layer, soops, ar); + if (RNA_boolean_get(op->ptr, "nested")) { + outliner_build_tree(bmain, scene, view_layer, soops, ar); - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_to_add, &data); + outliner_tree_traverse( + soops, &soops->tree, 0, TSE_SELECTED, collection_find_selected_to_add, &data); - if (data.error) { - BKE_report(op->reports, RPT_ERROR, "More than one collection is selected"); - return OPERATOR_CANCELLED; - } - } + if (data.error) { + BKE_report(op->reports, RPT_ERROR, "More than one collection is selected"); + return OPERATOR_CANCELLED; + } + } - if (data.collection == NULL || ID_IS_LINKED(data.collection)) { - data.collection = BKE_collection_master(scene); - } + if (data.collection == NULL || ID_IS_LINKED(data.collection)) { + data.collection = BKE_collection_master(scene); + } - if (ID_IS_LINKED(scene)) { - BKE_report(op->reports, RPT_ERROR, "Can't add a new collection to linked scene/collection"); - return OPERATOR_CANCELLED; - } + if (ID_IS_LINKED(scene)) { + BKE_report(op->reports, RPT_ERROR, "Can't add a new collection to linked scene/collection"); + return OPERATOR_CANCELLED; + } - BKE_collection_add( - bmain, - data.collection, - NULL); + BKE_collection_add(bmain, data.collection, NULL); - DEG_id_tag_update(&data.collection->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); + DEG_id_tag_update(&data.collection->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); - outliner_cleanup_tree(soops); - WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); - return OPERATOR_FINISHED; + outliner_cleanup_tree(soops); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + return OPERATOR_FINISHED; } void OUTLINER_OT_collection_new(wmOperatorType *ot) { - /* identifiers */ - ot->name = "New Collection"; - ot->idname = "OUTLINER_OT_collection_new"; - ot->description = "Add a new collection inside selected collection"; + /* identifiers */ + ot->name = "New Collection"; + ot->idname = "OUTLINER_OT_collection_new"; + ot->description = "Add a new collection inside selected collection"; - /* api callbacks */ - ot->exec = collection_new_exec; - ot->poll = ED_outliner_collections_editor_poll; + /* api callbacks */ + ot->exec = collection_new_exec; + ot->poll = ED_outliner_collections_editor_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - PropertyRNA *prop = RNA_def_boolean(ot->srna, "nested", true, "Nested", "Add as child of selected collection"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* properties */ + PropertyRNA *prop = RNA_def_boolean( + ot->srna, "nested", true, "Nested", "Add as child of selected collection"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /**************************** Delete Collection ******************************/ struct CollectionEditData { - Scene *scene; - SpaceOutliner *soops; - GSet *collections_to_edit; + Scene *scene; + SpaceOutliner *soops; + GSet *collections_to_edit; }; static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *customdata) { - struct CollectionEditData *data = customdata; - Collection *collection = outliner_collection_from_tree_element(te); + struct CollectionEditData *data = customdata; + Collection *collection = outliner_collection_from_tree_element(te); - if (!collection) { - return TRAVERSE_SKIP_CHILDS; - } + if (!collection) { + return TRAVERSE_SKIP_CHILDS; + } - if (collection->flag & COLLECTION_IS_MASTER) { - /* skip - showing warning/error message might be misleading - * when deleting multiple collections, so just do nothing */ - } - else { - /* Delete, duplicate and link don't edit children, those will come along - * with the parents. */ - BLI_gset_add(data->collections_to_edit, collection); - return TRAVERSE_SKIP_CHILDS; - } + if (collection->flag & COLLECTION_IS_MASTER) { + /* skip - showing warning/error message might be misleading + * when deleting multiple collections, so just do nothing */ + } + else { + /* Delete, duplicate and link don't edit children, those will come along + * with the parents. */ + BLI_gset_add(data->collections_to_edit, collection); + return TRAVERSE_SKIP_CHILDS; + } - return TRAVERSE_CONTINUE; + return TRAVERSE_CONTINUE; } static int collection_delete_exec(bContext *C, wmOperator *op) { - struct wmMsgBus *mbus = CTX_wm_message_bus(C); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - const Base *basact_prev = BASACT(view_layer); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - struct CollectionEditData data = {.scene = scene, .soops = soops,}; - bool hierarchy = RNA_boolean_get(op->ptr, "hierarchy"); - - data.collections_to_edit = BLI_gset_ptr_new(__func__); - - /* We first walk over and find the Collections we actually want to delete (ignoring duplicates). */ - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data); - - /* Effectively delete the collections. */ - GSetIterator collections_to_edit_iter; - GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); - - /* Test in case collection got deleted as part of another one. */ - if (BLI_findindex(&bmain->collections, collection) != -1) { - /* We cannot allow to delete collections that are indirectly linked, or that are used by (linked to...) - * other linked scene/collection. */ - bool skip = false; - if (ID_IS_LINKED(collection)) { - if (collection->id.tag & LIB_TAG_INDIRECT) { - skip = true; - } - else { - for (CollectionParent *cparent = collection->parents.first; cparent; cparent = cparent->next) { - Collection *parent = cparent->collection; - if (ID_IS_LINKED(parent)) { - skip = true; - break; - } - else if (parent->flag & COLLECTION_IS_MASTER) { - Scene *parent_scene = BKE_collection_master_scene_search(bmain, parent); - if (ID_IS_LINKED(parent_scene)) { - skip = true; - break; - } - } - } - } - } - - if (!skip) { - BKE_collection_delete(bmain, collection, hierarchy); - } - else { - BKE_reportf(op->reports, RPT_WARNING, - "Cannot delete linked collection '%s', it is used by other linked scenes/collections", - collection->id.name + 2); - } - } - } - - BLI_gset_free(data.collections_to_edit, NULL); - - DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); - - WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); - - if (basact_prev != BASACT(view_layer)) { - WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); - } - - return OPERATOR_FINISHED; + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + const Base *basact_prev = BASACT(view_layer); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + struct CollectionEditData data = { + .scene = scene, + .soops = soops, + }; + bool hierarchy = RNA_boolean_get(op->ptr, "hierarchy"); + + data.collections_to_edit = BLI_gset_ptr_new(__func__); + + /* We first walk over and find the Collections we actually want to delete (ignoring duplicates). */ + outliner_tree_traverse( + soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data); + + /* Effectively delete the collections. */ + GSetIterator collections_to_edit_iter; + GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { + Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + + /* Test in case collection got deleted as part of another one. */ + if (BLI_findindex(&bmain->collections, collection) != -1) { + /* We cannot allow to delete collections that are indirectly linked, or that are used by (linked to...) + * other linked scene/collection. */ + bool skip = false; + if (ID_IS_LINKED(collection)) { + if (collection->id.tag & LIB_TAG_INDIRECT) { + skip = true; + } + else { + for (CollectionParent *cparent = collection->parents.first; cparent; + cparent = cparent->next) { + Collection *parent = cparent->collection; + if (ID_IS_LINKED(parent)) { + skip = true; + break; + } + else if (parent->flag & COLLECTION_IS_MASTER) { + Scene *parent_scene = BKE_collection_master_scene_search(bmain, parent); + if (ID_IS_LINKED(parent_scene)) { + skip = true; + break; + } + } + } + } + } + + if (!skip) { + BKE_collection_delete(bmain, collection, hierarchy); + } + else { + BKE_reportf( + op->reports, + RPT_WARNING, + "Cannot delete linked collection '%s', it is used by other linked scenes/collections", + collection->id.name + 2); + } + } + } + + BLI_gset_free(data.collections_to_edit, NULL); + + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + + if (basact_prev != BASACT(view_layer)) { + WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); + } + + return OPERATOR_FINISHED; } void OUTLINER_OT_collection_delete(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Delete Collection"; - ot->idname = "OUTLINER_OT_collection_delete"; - ot->description = "Delete selected collections"; + /* identifiers */ + ot->name = "Delete Collection"; + ot->idname = "OUTLINER_OT_collection_delete"; + ot->description = "Delete selected collections"; - /* api callbacks */ - ot->exec = collection_delete_exec; - ot->poll = ED_outliner_collections_editor_poll; + /* api callbacks */ + ot->exec = collection_delete_exec; + ot->poll = ED_outliner_collections_editor_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - PropertyRNA *prop = RNA_def_boolean(ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* properties */ + PropertyRNA *prop = RNA_def_boolean( + ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /****************************** Select Objects *******************************/ struct CollectionObjectsSelectData { - bool error; - LayerCollection *layer_collection; + bool error; + LayerCollection *layer_collection; }; -static TreeTraversalAction outliner_find_first_selected_layer_collection(TreeElement *te, void *customdata) +static TreeTraversalAction outliner_find_first_selected_layer_collection(TreeElement *te, + void *customdata) { - struct CollectionObjectsSelectData *data = customdata; - TreeStoreElem *tselem = TREESTORE(te); + struct CollectionObjectsSelectData *data = customdata; + TreeStoreElem *tselem = TREESTORE(te); - switch (tselem->type) { - case TSE_LAYER_COLLECTION: - data->layer_collection = te->directdata; - return TRAVERSE_BREAK; - case TSE_R_LAYER: - case TSE_SCENE_COLLECTION_BASE: - case TSE_VIEW_COLLECTION_BASE: - return TRAVERSE_CONTINUE; - default: - return TRAVERSE_SKIP_CHILDS; - } + switch (tselem->type) { + case TSE_LAYER_COLLECTION: + data->layer_collection = te->directdata; + return TRAVERSE_BREAK; + case TSE_R_LAYER: + case TSE_SCENE_COLLECTION_BASE: + case TSE_VIEW_COLLECTION_BASE: + return TRAVERSE_CONTINUE; + default: + return TRAVERSE_SKIP_CHILDS; + } } static LayerCollection *outliner_active_layer_collection(bContext *C) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); - struct CollectionObjectsSelectData data = { - .layer_collection = NULL, - }; + struct CollectionObjectsSelectData data = { + .layer_collection = NULL, + }; - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_layer_collection, &data); - return data.layer_collection; + outliner_tree_traverse( + soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_layer_collection, &data); + return data.layer_collection; } static int collection_objects_select_exec(bContext *C, wmOperator *op) { - ViewLayer *view_layer = CTX_data_view_layer(C); - LayerCollection *layer_collection = outliner_active_layer_collection(C); - bool deselect = STREQ(op->idname, "OUTLINER_OT_collection_objects_deselect"); + ViewLayer *view_layer = CTX_data_view_layer(C); + LayerCollection *layer_collection = outliner_active_layer_collection(C); + bool deselect = STREQ(op->idname, "OUTLINER_OT_collection_objects_deselect"); - if (layer_collection == NULL) { - return OPERATOR_CANCELLED; - } + if (layer_collection == NULL) { + return OPERATOR_CANCELLED; + } - BKE_layer_collection_objects_select(view_layer, layer_collection, deselect); + BKE_layer_collection_objects_select(view_layer, layer_collection, deselect); - Scene *scene = CTX_data_scene(C); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene); + Scene *scene = CTX_data_scene(C); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_collection_objects_select(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Select Objects"; - ot->idname = "OUTLINER_OT_collection_objects_select"; - ot->description = "Select objects in collection"; + /* identifiers */ + ot->name = "Select Objects"; + ot->idname = "OUTLINER_OT_collection_objects_select"; + ot->description = "Select objects in collection"; - /* api callbacks */ - ot->exec = collection_objects_select_exec; - ot->poll = ED_outliner_collections_editor_poll; + /* api callbacks */ + ot->exec = collection_objects_select_exec; + ot->poll = ED_outliner_collections_editor_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } void OUTLINER_OT_collection_objects_deselect(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Deselect Objects"; - ot->idname = "OUTLINER_OT_collection_objects_deselect"; - ot->description = "Deselect objects in collection"; + /* identifiers */ + ot->name = "Deselect Objects"; + ot->idname = "OUTLINER_OT_collection_objects_deselect"; + ot->description = "Deselect objects in collection"; - /* api callbacks */ - ot->exec = collection_objects_select_exec; - ot->poll = ED_outliner_collections_editor_poll; + /* api callbacks */ + ot->exec = collection_objects_select_exec; + ot->poll = ED_outliner_collections_editor_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /************************** Duplicate Collection *****************************/ struct CollectionDuplicateData { - TreeElement *te; + TreeElement *te; }; -static TreeTraversalAction outliner_find_first_selected_collection(TreeElement *te, void *customdata) +static TreeTraversalAction outliner_find_first_selected_collection(TreeElement *te, + void *customdata) { - struct CollectionDuplicateData *data = customdata; - TreeStoreElem *tselem = TREESTORE(te); + struct CollectionDuplicateData *data = customdata; + TreeStoreElem *tselem = TREESTORE(te); - switch (tselem->type) { - case TSE_LAYER_COLLECTION: - data->te = te; - return TRAVERSE_BREAK; - case TSE_R_LAYER: - case TSE_SCENE_COLLECTION_BASE: - case TSE_VIEW_COLLECTION_BASE: - default: - return TRAVERSE_CONTINUE; - } + switch (tselem->type) { + case TSE_LAYER_COLLECTION: + data->te = te; + return TRAVERSE_BREAK; + case TSE_R_LAYER: + case TSE_SCENE_COLLECTION_BASE: + case TSE_VIEW_COLLECTION_BASE: + default: + return TRAVERSE_CONTINUE; + } } static TreeElement *outliner_active_collection(bContext *C) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); - struct CollectionDuplicateData data = { - .te = NULL, - }; + struct CollectionDuplicateData data = { + .te = NULL, + }; - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_first_selected_collection, &data); - return data.te; + 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) { - Main *bmain = CTX_data_main(C); - TreeElement *te = outliner_active_collection(C); - const bool linked = strstr(op->idname, "linked") != NULL; - - /* Can happen when calling from a key binding. */ - if (te == NULL) { - BKE_report(op->reports, RPT_ERROR, "No active collection"); - return OPERATOR_CANCELLED; - } - - Collection *collection = outliner_collection_from_tree_element(te); - Collection *parent = (te->parent) ? outliner_collection_from_tree_element(te->parent) : NULL; - - /* We are allowed to duplicated linked collections (they will become local IDs then), - * but we should not allow its parent to be a linked ID, ever. - * This can happen when a whole scene is linked e.g. */ - if (parent != NULL && ID_IS_LINKED(parent)) { - Scene *scene = CTX_data_scene(C); - parent = ID_IS_LINKED(scene) ? NULL : BKE_collection_master(scene); - } - else if (parent != NULL && (parent->flag & COLLECTION_IS_MASTER) != 0) { - Scene *scene = BKE_collection_master_scene_search(bmain, parent); - BLI_assert(scene != NULL); - if (ID_IS_LINKED(scene)) { - scene = CTX_data_scene(C); - parent = ID_IS_LINKED(scene) ? NULL : BKE_collection_master(scene); - } - } - - if (collection->flag & COLLECTION_IS_MASTER) { - BKE_report(op->reports, RPT_ERROR, "Can't duplicate the master collection"); - return OPERATOR_CANCELLED; - } - - if (parent == NULL) { - BKE_report(op->reports, RPT_WARNING, - "Could not find a valid parent collection for the new duplicate, " - "it won't be linked to any view layer"); - } - - BKE_collection_duplicate(bmain, parent, collection, true, true, !linked); - - DEG_relations_tag_update(bmain); - WM_main_add_notifier(NC_SCENE | ND_LAYER, CTX_data_scene(C)); - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + TreeElement *te = outliner_active_collection(C); + const bool linked = strstr(op->idname, "linked") != NULL; + + /* Can happen when calling from a key binding. */ + if (te == NULL) { + BKE_report(op->reports, RPT_ERROR, "No active collection"); + return OPERATOR_CANCELLED; + } + + Collection *collection = outliner_collection_from_tree_element(te); + Collection *parent = (te->parent) ? outliner_collection_from_tree_element(te->parent) : NULL; + + /* We are allowed to duplicated linked collections (they will become local IDs then), + * but we should not allow its parent to be a linked ID, ever. + * This can happen when a whole scene is linked e.g. */ + if (parent != NULL && ID_IS_LINKED(parent)) { + Scene *scene = CTX_data_scene(C); + parent = ID_IS_LINKED(scene) ? NULL : BKE_collection_master(scene); + } + else if (parent != NULL && (parent->flag & COLLECTION_IS_MASTER) != 0) { + Scene *scene = BKE_collection_master_scene_search(bmain, parent); + BLI_assert(scene != NULL); + if (ID_IS_LINKED(scene)) { + scene = CTX_data_scene(C); + parent = ID_IS_LINKED(scene) ? NULL : BKE_collection_master(scene); + } + } + + if (collection->flag & COLLECTION_IS_MASTER) { + BKE_report(op->reports, RPT_ERROR, "Can't duplicate the master collection"); + return OPERATOR_CANCELLED; + } + + if (parent == NULL) { + BKE_report(op->reports, + RPT_WARNING, + "Could not find a valid parent collection for the new duplicate, " + "it won't be linked to any view layer"); + } + + BKE_collection_duplicate(bmain, parent, collection, true, true, !linked); + + DEG_relations_tag_update(bmain); + WM_main_add_notifier(NC_SCENE | ND_LAYER, CTX_data_scene(C)); + + return OPERATOR_FINISHED; } void OUTLINER_OT_collection_duplicate_linked(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Duplicate Linked Collection"; - ot->idname = "OUTLINER_OT_collection_duplicate_linked"; - ot->description = "Recursively duplicate the collection, all its children and objects, with linked object data"; + /* identifiers */ + ot->name = "Duplicate Linked Collection"; + ot->idname = "OUTLINER_OT_collection_duplicate_linked"; + 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; + /* api callbacks */ + ot->exec = collection_duplicate_exec; + ot->poll = ED_outliner_collections_editor_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* 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"; + /* 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; - ot->poll = ED_outliner_collections_editor_poll; + /* api callbacks */ + ot->exec = collection_duplicate_exec; + ot->poll = ED_outliner_collections_editor_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /**************************** Link Collection ******************************/ static int collection_link_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - Collection *active_collection = CTX_data_layer_collection(C)->collection; - SpaceOutliner *soops = CTX_wm_space_outliner(C); - struct CollectionEditData data = {.scene = scene, .soops = soops,}; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Collection *active_collection = CTX_data_layer_collection(C)->collection; + SpaceOutliner *soops = CTX_wm_space_outliner(C); + struct CollectionEditData data = { + .scene = scene, + .soops = soops, + }; - if (ID_IS_LINKED(active_collection) || - ((active_collection->flag & COLLECTION_IS_MASTER) && ID_IS_LINKED(scene))) - { - BKE_report(op->reports, RPT_ERROR, "Cannot add a colection to a linked collection/scene"); - return OPERATOR_CANCELLED; - } + if (ID_IS_LINKED(active_collection) || + ((active_collection->flag & COLLECTION_IS_MASTER) && ID_IS_LINKED(scene))) { + BKE_report(op->reports, RPT_ERROR, "Cannot add a colection to a linked collection/scene"); + return OPERATOR_CANCELLED; + } - data.collections_to_edit = BLI_gset_ptr_new(__func__); + data.collections_to_edit = BLI_gset_ptr_new(__func__); - /* We first walk over and find the Collections we actually want to link (ignoring duplicates). */ - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data); + /* We first walk over and find the Collections we actually want to link (ignoring duplicates). */ + outliner_tree_traverse( + soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data); - /* Effectively link the collections. */ - GSetIterator collections_to_edit_iter; - GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); - BKE_collection_child_add(bmain, active_collection, collection); - id_fake_user_clear(&collection->id); - } + /* Effectively link the collections. */ + GSetIterator collections_to_edit_iter; + GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { + Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + BKE_collection_child_add(bmain, active_collection, collection); + id_fake_user_clear(&collection->id); + } - BLI_gset_free(data.collections_to_edit, NULL); + BLI_gset_free(data.collections_to_edit, NULL); - DEG_id_tag_update(&active_collection->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); + DEG_id_tag_update(&active_collection->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); - WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_collection_link(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Link Collection"; - ot->idname = "OUTLINER_OT_collection_link"; - ot->description = "Link selected collections to active scene"; + /* identifiers */ + ot->name = "Link Collection"; + ot->idname = "OUTLINER_OT_collection_link"; + ot->description = "Link selected collections to active scene"; - /* api callbacks */ - ot->exec = collection_link_exec; - ot->poll = ED_outliner_collections_editor_poll; + /* api callbacks */ + ot->exec = collection_link_exec; + ot->poll = ED_outliner_collections_editor_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /************************** Instance Collection ******************************/ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op)) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - struct CollectionEditData data = {.scene = scene, .soops = soops,}; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + struct CollectionEditData data = { + .scene = scene, + .soops = soops, + }; - data.collections_to_edit = BLI_gset_ptr_new(__func__); + data.collections_to_edit = BLI_gset_ptr_new(__func__); - /* We first walk over and find the Collections we actually want to instance (ignoring duplicates). */ - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data); + /* We first walk over and find the Collections we actually want to instance (ignoring duplicates). */ + outliner_tree_traverse( + soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data); - /* Find an active collection to add to, that doesn't give dependency cycles. */ - LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer); + /* Find an active collection to add to, that doesn't give dependency cycles. */ + LayerCollection *active_lc = BKE_layer_collection_get_active(view_layer); - GSetIterator collections_to_edit_iter; - GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + GSetIterator collections_to_edit_iter; + GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { + Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); - while (BKE_collection_find_cycle(active_lc->collection, collection)) { - active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc); - } - } + while (BKE_collection_find_cycle(active_lc->collection, collection)) { + active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc); + } + } - /* Effectively instance the collections. */ - GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); - Object *ob = ED_object_add_type(C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, NULL, false, 0); - ob->instance_collection = collection; - ob->transflag |= OB_DUPLICOLLECTION; - id_lib_extern(&collection->id); - } + /* Effectively instance the collections. */ + GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { + Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + Object *ob = ED_object_add_type( + C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, NULL, false, 0); + ob->instance_collection = collection; + ob->transflag |= OB_DUPLICOLLECTION; + id_lib_extern(&collection->id); + } - BLI_gset_free(data.collections_to_edit, NULL); + BLI_gset_free(data.collections_to_edit, NULL); - DEG_relations_tag_update(bmain); + DEG_relations_tag_update(bmain); - WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_collection_instance(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Instance Collection"; - ot->idname = "OUTLINER_OT_collection_instance"; - ot->description = "Instance selected collections to active scene"; + /* identifiers */ + ot->name = "Instance Collection"; + ot->idname = "OUTLINER_OT_collection_instance"; + ot->description = "Instance selected collections to active scene"; - /* api callbacks */ - ot->exec = collection_instance_exec; - ot->poll = ED_outliner_collections_editor_poll; + /* api callbacks */ + ot->exec = collection_instance_exec; + ot->poll = ED_outliner_collections_editor_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /************************** Exclude Collection ******************************/ static TreeTraversalAction layer_collection_find_data_to_edit(TreeElement *te, void *customdata) { - struct CollectionEditData *data = customdata; - TreeStoreElem *tselem = TREESTORE(te); + struct CollectionEditData *data = customdata; + TreeStoreElem *tselem = TREESTORE(te); - if (!(tselem && tselem->type == TSE_LAYER_COLLECTION)) { - return TRAVERSE_CONTINUE; - } + if (!(tselem && tselem->type == TSE_LAYER_COLLECTION)) { + return TRAVERSE_CONTINUE; + } - LayerCollection *lc = te->directdata; + LayerCollection *lc = te->directdata; - if (lc->collection->flag & COLLECTION_IS_MASTER) { - /* skip - showing warning/error message might be misleading - * when deleting multiple collections, so just do nothing */ - } - else { - /* Delete, duplicate and link don't edit children, those will come along - * with the parents. */ - BLI_gset_add(data->collections_to_edit, lc); - } + if (lc->collection->flag & COLLECTION_IS_MASTER) { + /* skip - showing warning/error message might be misleading + * when deleting multiple collections, so just do nothing */ + } + else { + /* Delete, duplicate and link don't edit children, those will come along + * with the parents. */ + BLI_gset_add(data->collections_to_edit, lc); + } - return TRAVERSE_CONTINUE; + return TRAVERSE_CONTINUE; } static bool collections_view_layer_poll(bContext *C, bool clear, int flag) { - /* Poll function so the right click menu show current state of selected collections. */ - SpaceOutliner *soops = CTX_wm_space_outliner(C); - if (!(soops && soops->outlinevis == SO_VIEW_LAYER)) { - return false; - } + /* Poll function so the right click menu show current state of selected collections. */ + SpaceOutliner *soops = CTX_wm_space_outliner(C); + if (!(soops && soops->outlinevis == SO_VIEW_LAYER)) { + return false; + } - Scene *scene = CTX_data_scene(C); - struct CollectionEditData data = {.scene = scene, .soops = soops,}; - data.collections_to_edit = BLI_gset_ptr_new(__func__); - bool result = false; + Scene *scene = CTX_data_scene(C); + struct CollectionEditData data = { + .scene = scene, + .soops = soops, + }; + data.collections_to_edit = BLI_gset_ptr_new(__func__); + bool result = false; - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data); + outliner_tree_traverse( + soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data); - GSetIterator collections_to_edit_iter; - GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter); + GSetIterator collections_to_edit_iter; + GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { + LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter); - if (clear && (lc->flag & flag)) { - result = true; - } - else if (!clear && !(lc->flag & flag)) { - result = true; - } - } + if (clear && (lc->flag & flag)) { + result = true; + } + else if (!clear && !(lc->flag & flag)) { + result = true; + } + } - BLI_gset_free(data.collections_to_edit, NULL); - return result; + BLI_gset_free(data.collections_to_edit, NULL); + return result; } static bool collections_exclude_set_poll(bContext *C) { - return collections_view_layer_poll(C, false, LAYER_COLLECTION_EXCLUDE); + return collections_view_layer_poll(C, false, LAYER_COLLECTION_EXCLUDE); } static bool collections_exclude_clear_poll(bContext *C) { - return collections_view_layer_poll(C, true, LAYER_COLLECTION_EXCLUDE); + return collections_view_layer_poll(C, true, LAYER_COLLECTION_EXCLUDE); } static bool collections_holdout_set_poll(bContext *C) { - return collections_view_layer_poll(C, false, LAYER_COLLECTION_HOLDOUT); + return collections_view_layer_poll(C, false, LAYER_COLLECTION_HOLDOUT); } static bool collections_holdout_clear_poll(bContext *C) { - return collections_view_layer_poll(C, true, LAYER_COLLECTION_HOLDOUT); + return collections_view_layer_poll(C, true, LAYER_COLLECTION_HOLDOUT); } static bool collections_indirect_only_set_poll(bContext *C) { - return collections_view_layer_poll(C, false, LAYER_COLLECTION_INDIRECT_ONLY); + return collections_view_layer_poll(C, false, LAYER_COLLECTION_INDIRECT_ONLY); } static bool collections_indirect_only_clear_poll(bContext *C) { - return collections_view_layer_poll(C, true, LAYER_COLLECTION_INDIRECT_ONLY); + return collections_view_layer_poll(C, true, LAYER_COLLECTION_INDIRECT_ONLY); } static void layer_collection_flag_recursive_set(LayerCollection *lc, int flag) { - for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { - if (lc->flag & flag) { - nlc->flag |= flag; - } - else { - nlc->flag &= ~flag; - } + for (LayerCollection *nlc = lc->layer_collections.first; nlc; nlc = nlc->next) { + if (lc->flag & flag) { + nlc->flag |= flag; + } + else { + nlc->flag &= ~flag; + } - layer_collection_flag_recursive_set(nlc, flag); - } + layer_collection_flag_recursive_set(nlc, flag); + } } static int collection_view_layer_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - struct CollectionEditData data = {.scene = scene, .soops = soops,}; - bool clear = strstr(op->idname, "clear") != NULL; - int flag = strstr(op->idname, "holdout") ? LAYER_COLLECTION_HOLDOUT : - strstr(op->idname, "indirect_only") ? LAYER_COLLECTION_INDIRECT_ONLY : - LAYER_COLLECTION_EXCLUDE; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + struct CollectionEditData data = { + .scene = scene, + .soops = soops, + }; + bool clear = strstr(op->idname, "clear") != NULL; + int flag = strstr(op->idname, "holdout") ? + LAYER_COLLECTION_HOLDOUT : + strstr(op->idname, "indirect_only") ? LAYER_COLLECTION_INDIRECT_ONLY : + LAYER_COLLECTION_EXCLUDE; - data.collections_to_edit = BLI_gset_ptr_new(__func__); + data.collections_to_edit = BLI_gset_ptr_new(__func__); - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data); + outliner_tree_traverse( + soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data); - GSetIterator collections_to_edit_iter; - GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter); + GSetIterator collections_to_edit_iter; + GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { + LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter); - if (clear) { - lc->flag &= ~flag; - } - else { - lc->flag |= flag; - } + if (clear) { + lc->flag &= ~flag; + } + else { + lc->flag |= flag; + } - layer_collection_flag_recursive_set(lc, flag); - } + layer_collection_flag_recursive_set(lc, flag); + } - BLI_gset_free(data.collections_to_edit, NULL); + BLI_gset_free(data.collections_to_edit, NULL); - BKE_layer_collection_sync(scene, view_layer); - DEG_relations_tag_update(bmain); + BKE_layer_collection_sync(scene, view_layer); + DEG_relations_tag_update(bmain); - WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_collection_exclude_set(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Set Exclude"; - ot->idname = "OUTLINER_OT_collection_exclude_set"; - ot->description = "Exclude collection from the active view layer"; + /* identifiers */ + ot->name = "Set Exclude"; + ot->idname = "OUTLINER_OT_collection_exclude_set"; + ot->description = "Exclude collection from the active view layer"; - /* api callbacks */ - ot->exec = collection_view_layer_exec; - ot->poll = collections_exclude_set_poll; + /* api callbacks */ + ot->exec = collection_view_layer_exec; + ot->poll = collections_exclude_set_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } void OUTLINER_OT_collection_exclude_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Exclude"; - ot->idname = "OUTLINER_OT_collection_exclude_clear"; - ot->description = "Include collection in the active view layer"; + /* identifiers */ + ot->name = "Clear Exclude"; + ot->idname = "OUTLINER_OT_collection_exclude_clear"; + ot->description = "Include collection in the active view layer"; - /* api callbacks */ - ot->exec = collection_view_layer_exec; - ot->poll = collections_exclude_clear_poll; + /* api callbacks */ + ot->exec = collection_view_layer_exec; + ot->poll = collections_exclude_clear_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } void OUTLINER_OT_collection_holdout_set(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Set Holdout"; - ot->idname = "OUTLINER_OT_collection_holdout_set"; - ot->description = "Mask collection in the active view layer"; + /* identifiers */ + ot->name = "Set Holdout"; + ot->idname = "OUTLINER_OT_collection_holdout_set"; + ot->description = "Mask collection in the active view layer"; - /* api callbacks */ - ot->exec = collection_view_layer_exec; - ot->poll = collections_holdout_set_poll; + /* api callbacks */ + ot->exec = collection_view_layer_exec; + ot->poll = collections_holdout_set_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } void OUTLINER_OT_collection_holdout_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Holdout"; - ot->idname = "OUTLINER_OT_collection_holdout_clear"; - ot->description = "Clear masking of collection in the active view layer"; + /* identifiers */ + ot->name = "Clear Holdout"; + ot->idname = "OUTLINER_OT_collection_holdout_clear"; + ot->description = "Clear masking of collection in the active view layer"; - /* api callbacks */ - ot->exec = collection_view_layer_exec; - ot->poll = collections_holdout_clear_poll; + /* api callbacks */ + ot->exec = collection_view_layer_exec; + ot->poll = collections_holdout_clear_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } void OUTLINER_OT_collection_indirect_only_set(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Set Indirect Only"; - ot->idname = "OUTLINER_OT_collection_indirect_only_set"; - ot->description = "Set collection to only contribute indirectly (through shadows and reflections) in the view layer"; + /* identifiers */ + ot->name = "Set Indirect Only"; + ot->idname = "OUTLINER_OT_collection_indirect_only_set"; + ot->description = + "Set collection to only contribute indirectly (through shadows and reflections) in the view " + "layer"; - /* api callbacks */ - ot->exec = collection_view_layer_exec; - ot->poll = collections_indirect_only_set_poll; + /* api callbacks */ + ot->exec = collection_view_layer_exec; + ot->poll = collections_indirect_only_set_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } void OUTLINER_OT_collection_indirect_only_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Clear Indirect Only"; - ot->idname = "OUTLINER_OT_collection_indirect_only_clear"; - ot->description = "Clear collection contributing only indirectly in the view layer"; + /* identifiers */ + ot->name = "Clear Indirect Only"; + ot->idname = "OUTLINER_OT_collection_indirect_only_clear"; + ot->description = "Clear collection contributing only indirectly in the view layer"; - /* api callbacks */ - ot->exec = collection_view_layer_exec; - ot->poll = collections_indirect_only_clear_poll; + /* api callbacks */ + ot->exec = collection_view_layer_exec; + ot->poll = collections_indirect_only_clear_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /************************** Visibility Operators ******************************/ static int collection_isolate_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - const bool extend = RNA_boolean_get(op->ptr, "extend"); - bool depsgraph_changed = false; - struct CollectionEditData data = {.scene = scene, .soops = soops,}; - data.collections_to_edit = BLI_gset_ptr_new(__func__); - - /* Hide all collections before the isolate function - needed in order to support multiple selected collections. */ - if (!extend) { - LayerCollection *lc_master = view_layer->layer_collections.first; - for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; lc_iter = lc_iter->next) { - lc_iter->flag |= LAYER_COLLECTION_RESTRICT_VIEW; - layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_RESTRICT_VIEW); - } - } - - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data); - - GSetIterator collections_to_edit_iter; - GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); - depsgraph_changed |= BKE_layer_collection_isolate(scene, view_layer, layer_collection, true); - } - BLI_gset_free(data.collections_to_edit, NULL); - - BKE_layer_collection_sync(scene, view_layer); - DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - - if (depsgraph_changed) { - DEG_relations_tag_update(CTX_data_main(C)); - } - - WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + bool depsgraph_changed = false; + struct CollectionEditData data = { + .scene = scene, + .soops = soops, + }; + data.collections_to_edit = BLI_gset_ptr_new(__func__); + + /* Hide all collections before the isolate function - needed in order to support multiple selected collections. */ + if (!extend) { + LayerCollection *lc_master = view_layer->layer_collections.first; + for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; + lc_iter = lc_iter->next) { + lc_iter->flag |= LAYER_COLLECTION_RESTRICT_VIEW; + layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_RESTRICT_VIEW); + } + } + + outliner_tree_traverse( + soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data); + + GSetIterator collections_to_edit_iter; + GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { + LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + depsgraph_changed |= BKE_layer_collection_isolate(scene, view_layer, layer_collection, true); + } + BLI_gset_free(data.collections_to_edit, NULL); + + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + + if (depsgraph_changed) { + DEG_relations_tag_update(CTX_data_main(C)); + } + + WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); + return OPERATOR_FINISHED; } static int collection_isolate_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - PropertyRNA *prop = RNA_struct_find_property(op->ptr, "extend"); - if (!RNA_property_is_set(op->ptr, prop) && (event->shift)) { - RNA_property_boolean_set(op->ptr, prop, true); - } - return collection_isolate_exec(C, op); + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "extend"); + if (!RNA_property_is_set(op->ptr, prop) && (event->shift)) { + RNA_property_boolean_set(op->ptr, prop, true); + } + return collection_isolate_exec(C, op); } void OUTLINER_OT_collection_isolate(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Isolate Collection"; - ot->idname = "OUTLINER_OT_collection_isolate"; - ot->description = "Hide all but this collection and its parents"; + /* identifiers */ + ot->name = "Isolate Collection"; + ot->idname = "OUTLINER_OT_collection_isolate"; + ot->description = "Hide all but this collection and its parents"; - /* api callbacks */ - ot->exec = collection_isolate_exec; - ot->invoke = collection_isolate_invoke; - ot->poll = ED_outliner_collections_editor_poll; + /* api callbacks */ + ot->exec = collection_isolate_exec; + ot->invoke = collection_isolate_invoke; + ot->poll = ED_outliner_collections_editor_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - PropertyRNA *prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend current visible collections"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* properties */ + PropertyRNA *prop = RNA_def_boolean( + ot->srna, "extend", false, "Extend", "Extend current visible collections"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } static bool collection_show_poll(bContext *C) { - return collections_view_layer_poll(C, true, LAYER_COLLECTION_RESTRICT_VIEW); + return collections_view_layer_poll(C, true, LAYER_COLLECTION_RESTRICT_VIEW); } static bool collection_hide_poll(bContext *C) { - return collections_view_layer_poll(C, false, LAYER_COLLECTION_RESTRICT_VIEW); + return collections_view_layer_poll(C, false, LAYER_COLLECTION_RESTRICT_VIEW); } static bool collection_inside_poll(bContext *C) { - if (!ED_outliner_collections_editor_poll(C)) { - return false; - } - return outliner_active_layer_collection(C) != NULL; + if (!ED_outliner_collections_editor_poll(C)) { + return false; + } + return outliner_active_layer_collection(C) != NULL; } static int collection_visibility_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - const bool is_inside = strstr(op->idname, "inside") != NULL; - const bool show = strstr(op->idname, "show") != NULL; - bool depsgraph_changed = false; - struct CollectionEditData data = {.scene = scene, .soops = soops,}; - data.collections_to_edit = BLI_gset_ptr_new(__func__); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + const bool is_inside = strstr(op->idname, "inside") != NULL; + const bool show = strstr(op->idname, "show") != NULL; + bool depsgraph_changed = false; + struct CollectionEditData data = { + .scene = scene, + .soops = soops, + }; + data.collections_to_edit = BLI_gset_ptr_new(__func__); - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data); + outliner_tree_traverse( + soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data); - GSetIterator collections_to_edit_iter; - GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); - depsgraph_changed |= BKE_layer_collection_set_visible(view_layer, layer_collection, show, is_inside); - } - BLI_gset_free(data.collections_to_edit, NULL); + GSetIterator collections_to_edit_iter; + GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { + LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + depsgraph_changed |= BKE_layer_collection_set_visible( + view_layer, layer_collection, show, is_inside); + } + BLI_gset_free(data.collections_to_edit, NULL); - BKE_layer_collection_sync(scene, view_layer); - DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - if (depsgraph_changed) { - DEG_relations_tag_update(CTX_data_main(C)); - } + if (depsgraph_changed) { + DEG_relations_tag_update(CTX_data_main(C)); + } - WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); - return OPERATOR_FINISHED; + WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); + return OPERATOR_FINISHED; } void OUTLINER_OT_collection_show(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Show Collection"; - ot->idname = "OUTLINER_OT_collection_show"; - ot->description = "Show the collection in this view layer"; + /* identifiers */ + ot->name = "Show Collection"; + ot->idname = "OUTLINER_OT_collection_show"; + ot->description = "Show the collection in this view layer"; - /* api callbacks */ - ot->exec = collection_visibility_exec; - ot->poll = collection_show_poll; + /* api callbacks */ + ot->exec = collection_visibility_exec; + ot->poll = collection_show_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } void OUTLINER_OT_collection_hide(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Hide Collection"; - ot->idname = "OUTLINER_OT_collection_hide"; - ot->description = "Hide the collection in this view layer"; + /* identifiers */ + ot->name = "Hide Collection"; + ot->idname = "OUTLINER_OT_collection_hide"; + ot->description = "Hide the collection in this view layer"; - /* api callbacks */ - ot->exec = collection_visibility_exec; - ot->poll = collection_hide_poll; + /* api callbacks */ + ot->exec = collection_visibility_exec; + ot->poll = collection_hide_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } void OUTLINER_OT_collection_show_inside(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Show Inside Collection"; - ot->idname = "OUTLINER_OT_collection_show_inside"; - ot->description = "Show all the objects and collections inside the collection"; + /* identifiers */ + ot->name = "Show Inside Collection"; + ot->idname = "OUTLINER_OT_collection_show_inside"; + ot->description = "Show all the objects and collections inside the collection"; - /* api callbacks */ - ot->exec = collection_visibility_exec; - ot->poll = collection_inside_poll; + /* api callbacks */ + ot->exec = collection_visibility_exec; + ot->poll = collection_inside_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } void OUTLINER_OT_collection_hide_inside(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Hide Inside Collection"; - ot->idname = "OUTLINER_OT_collection_hide_inside"; - ot->description = "Hide all the objects and collections inside the collection"; + /* identifiers */ + ot->name = "Hide Inside Collection"; + ot->idname = "OUTLINER_OT_collection_hide_inside"; + ot->description = "Hide all the objects and collections inside the collection"; - /* api callbacks */ - ot->exec = collection_visibility_exec; - ot->poll = collection_inside_poll; + /* api callbacks */ + ot->exec = collection_visibility_exec; + ot->poll = collection_inside_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static bool collection_flag_poll(bContext *C, bool clear, int flag) { - if (!ED_outliner_collections_editor_poll(C)) { - return false; - } + if (!ED_outliner_collections_editor_poll(C)) { + return false; + } - TreeElement *te = outliner_active_collection(C); - if (te == NULL) { - return false; - } + TreeElement *te = outliner_active_collection(C); + if (te == NULL) { + return false; + } - Collection *collection = outliner_collection_from_tree_element(te); - if (collection == NULL) { - return false; - } + Collection *collection = outliner_collection_from_tree_element(te); + if (collection == NULL) { + return false; + } - if (clear && (collection->flag & flag)) { - return true; - } - else if (!clear && !(collection->flag & flag)) { - return true; - } + if (clear && (collection->flag & flag)) { + return true; + } + else if (!clear && !(collection->flag & flag)) { + return true; + } - return false; + return false; } static bool collection_enable_poll(bContext *C) { - return collection_flag_poll(C, true, COLLECTION_RESTRICT_VIEW); + return collection_flag_poll(C, true, COLLECTION_RESTRICT_VIEW); } static bool collection_disable_poll(bContext *C) { - return collection_flag_poll(C, false, COLLECTION_RESTRICT_VIEW); + return collection_flag_poll(C, false, COLLECTION_RESTRICT_VIEW); } static bool collection_enable_render_poll(bContext *C) { - return collection_flag_poll(C, true, COLLECTION_RESTRICT_RENDER); + return collection_flag_poll(C, true, COLLECTION_RESTRICT_RENDER); } static bool collection_disable_render_poll(bContext *C) { - return collection_flag_poll(C, false, COLLECTION_RESTRICT_RENDER); + return collection_flag_poll(C, false, COLLECTION_RESTRICT_RENDER); } static int collection_flag_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - const bool is_render = strstr(op->idname, "render"); - const bool clear = strstr(op->idname, "show") || strstr(op->idname, "enable"); - int flag = is_render ? COLLECTION_RESTRICT_RENDER : COLLECTION_RESTRICT_VIEW; - struct CollectionEditData data = {.scene = scene, .soops = soops,}; - data.collections_to_edit = BLI_gset_ptr_new(__func__); - const bool has_layer_collection = soops->outlinevis == SO_VIEW_LAYER; - - if (has_layer_collection) { - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data); - GSetIterator collections_to_edit_iter; - GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); - Collection *collection = layer_collection->collection; - if (ID_IS_LINKED(collection)) { - continue; - } - if (clear) { - collection->flag &= ~flag; - } - else { - collection->flag |= flag; - } - - /* Make sure (at least for this view layer) the collection is visible. */ - if (clear && !is_render) { - layer_collection->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW; - } - } - BLI_gset_free(data.collections_to_edit, NULL); - } - else { - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data); - GSetIterator collections_to_edit_iter; - GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); - - if (clear) { - collection->flag &= ~flag; - } - else { - collection->flag |= flag; - } - } - BLI_gset_free(data.collections_to_edit, NULL); - } - - BKE_layer_collection_sync(scene, view_layer); - DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - - if (!is_render) { - DEG_relations_tag_update(CTX_data_main(C)); - } - - WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + const bool is_render = strstr(op->idname, "render"); + const bool clear = strstr(op->idname, "show") || strstr(op->idname, "enable"); + int flag = is_render ? COLLECTION_RESTRICT_RENDER : COLLECTION_RESTRICT_VIEW; + struct CollectionEditData data = { + .scene = scene, + .soops = soops, + }; + data.collections_to_edit = BLI_gset_ptr_new(__func__); + const bool has_layer_collection = soops->outlinevis == SO_VIEW_LAYER; + + if (has_layer_collection) { + outliner_tree_traverse( + soops, &soops->tree, 0, TSE_SELECTED, layer_collection_find_data_to_edit, &data); + GSetIterator collections_to_edit_iter; + GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { + LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + Collection *collection = layer_collection->collection; + if (ID_IS_LINKED(collection)) { + continue; + } + if (clear) { + collection->flag &= ~flag; + } + else { + collection->flag |= flag; + } + + /* Make sure (at least for this view layer) the collection is visible. */ + if (clear && !is_render) { + layer_collection->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW; + } + } + BLI_gset_free(data.collections_to_edit, NULL); + } + else { + outliner_tree_traverse( + soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_edit, &data); + GSetIterator collections_to_edit_iter; + GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { + Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + + if (clear) { + collection->flag &= ~flag; + } + else { + collection->flag |= flag; + } + } + BLI_gset_free(data.collections_to_edit, NULL); + } + + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + + if (!is_render) { + DEG_relations_tag_update(CTX_data_main(C)); + } + + WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); + return OPERATOR_FINISHED; } void OUTLINER_OT_collection_enable(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Enable Collection"; - ot->idname = "OUTLINER_OT_collection_enable"; - ot->description = "Enable viewport drawing in the view layers"; + /* identifiers */ + ot->name = "Enable Collection"; + ot->idname = "OUTLINER_OT_collection_enable"; + ot->description = "Enable viewport drawing in the view layers"; - /* api callbacks */ - ot->exec = collection_flag_exec; - ot->poll = collection_enable_poll; + /* api callbacks */ + ot->exec = collection_flag_exec; + ot->poll = collection_enable_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } void OUTLINER_OT_collection_disable(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Disable Collection"; - ot->idname = "OUTLINER_OT_collection_disable"; - ot->description = "Disable viewport drawing in the view layers"; + /* identifiers */ + ot->name = "Disable Collection"; + ot->idname = "OUTLINER_OT_collection_disable"; + ot->description = "Disable viewport drawing in the view layers"; - /* api callbacks */ - ot->exec = collection_flag_exec; - ot->poll = collection_disable_poll; + /* api callbacks */ + ot->exec = collection_flag_exec; + ot->poll = collection_disable_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } void OUTLINER_OT_collection_enable_render(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Enable Collection in Render"; - ot->idname = "OUTLINER_OT_collection_enable_render"; - ot->description = "Render the collection"; + /* identifiers */ + ot->name = "Enable Collection in Render"; + ot->idname = "OUTLINER_OT_collection_enable_render"; + ot->description = "Render the collection"; - /* api callbacks */ - ot->exec = collection_flag_exec; - ot->poll = collection_enable_render_poll; + /* api callbacks */ + ot->exec = collection_flag_exec; + ot->poll = collection_enable_render_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } void OUTLINER_OT_collection_disable_render(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Disable Collection in Render"; - ot->idname = "OUTLINER_OT_collection_disable_render"; - ot->description = "Do not render this collection"; + /* identifiers */ + ot->name = "Disable Collection in Render"; + ot->idname = "OUTLINER_OT_collection_disable_render"; + ot->description = "Do not render this collection"; - /* api callbacks */ - ot->exec = collection_flag_exec; - ot->poll = collection_disable_render_poll; + /* api callbacks */ + ot->exec = collection_flag_exec; + ot->poll = collection_disable_render_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } struct OutlinerHideEditData { - Scene *scene; - ViewLayer *view_layer; - SpaceOutliner *soops; - GSet *collections_to_edit; - GSet *bases_to_edit; + Scene *scene; + ViewLayer *view_layer; + SpaceOutliner *soops; + GSet *collections_to_edit; + GSet *bases_to_edit; }; static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void *customdata) { - struct OutlinerHideEditData *data = customdata; - TreeStoreElem *tselem = TREESTORE(te); + struct OutlinerHideEditData *data = customdata; + TreeStoreElem *tselem = TREESTORE(te); - if (tselem == NULL) { - return TRAVERSE_CONTINUE; - } + if (tselem == NULL) { + return TRAVERSE_CONTINUE; + } - if (tselem->type == TSE_LAYER_COLLECTION) { - LayerCollection *lc = te->directdata; + if (tselem->type == TSE_LAYER_COLLECTION) { + LayerCollection *lc = te->directdata; - if (lc->collection->flag & COLLECTION_IS_MASTER) { - /* Skip - showing warning/error message might be misleading - * when deleting multiple collections, so just do nothing. */ - } - else { - /* Delete, duplicate and link don't edit children, - * those will come along with the parents. */ - BLI_gset_add(data->collections_to_edit, lc); - } - } - else if (tselem->type == 0 && te->idcode == ID_OB) { - Object *ob = (Object *)tselem->id; - Base *base = BKE_view_layer_base_find(data->view_layer, ob); - BLI_gset_add(data->bases_to_edit, base); - } + if (lc->collection->flag & COLLECTION_IS_MASTER) { + /* Skip - showing warning/error message might be misleading + * when deleting multiple collections, so just do nothing. */ + } + else { + /* Delete, duplicate and link don't edit children, + * those will come along with the parents. */ + BLI_gset_add(data->collections_to_edit, lc); + } + } + else if (tselem->type == 0 && te->idcode == ID_OB) { + Object *ob = (Object *)tselem->id; + Base *base = BKE_view_layer_base_find(data->view_layer, ob); + BLI_gset_add(data->bases_to_edit, base); + } - return TRAVERSE_CONTINUE; + return TRAVERSE_CONTINUE; } static int outliner_hide_exec(bContext *C, wmOperator *UNUSED(op)) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - struct OutlinerHideEditData data = {.scene = scene, .view_layer = view_layer, .soops = soops,}; - data.collections_to_edit = BLI_gset_ptr_new("outliner_hide_exec__collections_to_edit"); - data.bases_to_edit = BLI_gset_ptr_new("outliner_hide_exec__bases_to_edit"); - - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_hide_find_data_to_edit, &data); - - GSetIterator collections_to_edit_iter; - GSET_ITER(collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); - BKE_layer_collection_set_visible(view_layer, layer_collection, false, false); - } - BLI_gset_free(data.collections_to_edit, NULL); - - GSetIterator bases_to_edit_iter; - GSET_ITER(bases_to_edit_iter, data.bases_to_edit) { - Base *base = BLI_gsetIterator_getKey(&bases_to_edit_iter); - base->flag |= BASE_HIDDEN; - } - BLI_gset_free(data.bases_to_edit, NULL); - - BKE_layer_collection_sync(scene, view_layer); - DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - - WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + struct OutlinerHideEditData data = { + .scene = scene, + .view_layer = view_layer, + .soops = soops, + }; + data.collections_to_edit = BLI_gset_ptr_new("outliner_hide_exec__collections_to_edit"); + data.bases_to_edit = BLI_gset_ptr_new("outliner_hide_exec__bases_to_edit"); + + outliner_tree_traverse( + soops, &soops->tree, 0, TSE_SELECTED, outliner_hide_find_data_to_edit, &data); + + GSetIterator collections_to_edit_iter; + GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { + LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + BKE_layer_collection_set_visible(view_layer, layer_collection, false, false); + } + BLI_gset_free(data.collections_to_edit, NULL); + + GSetIterator bases_to_edit_iter; + GSET_ITER (bases_to_edit_iter, data.bases_to_edit) { + Base *base = BLI_gsetIterator_getKey(&bases_to_edit_iter); + base->flag |= BASE_HIDDEN; + } + BLI_gset_free(data.bases_to_edit, NULL); + + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + + WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); + return OPERATOR_FINISHED; } void OUTLINER_OT_hide(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Hide"; - ot->idname = "OUTLINER_OT_hide"; - ot->description = "Hide selected objects and collections"; + /* identifiers */ + ot->name = "Hide"; + ot->idname = "OUTLINER_OT_hide"; + ot->description = "Hide selected objects and collections"; - /* api callbacks */ - ot->exec = outliner_hide_exec; - ot->poll = outliner_view_layer_collections_editor_poll; + /* api callbacks */ + ot->exec = outliner_hide_exec; + ot->poll = outliner_view_layer_collections_editor_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op)) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); - /* Unhide all the collections. */ - LayerCollection *lc_master = view_layer->layer_collections.first; - for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; lc_iter = lc_iter->next) { - lc_iter->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW; - layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_RESTRICT_VIEW); - } + /* Unhide all the collections. */ + LayerCollection *lc_master = view_layer->layer_collections.first; + for (LayerCollection *lc_iter = lc_master->layer_collections.first; lc_iter; + lc_iter = lc_iter->next) { + lc_iter->flag &= ~LAYER_COLLECTION_RESTRICT_VIEW; + layer_collection_flag_recursive_set(lc_iter, LAYER_COLLECTION_RESTRICT_VIEW); + } - /* Unhide all objects. */ - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - base->flag &= ~BASE_HIDDEN; - } + /* Unhide all objects. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + base->flag &= ~BASE_HIDDEN; + } - BKE_layer_collection_sync(scene, view_layer); - DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); - return OPERATOR_FINISHED; + WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); + return OPERATOR_FINISHED; } void OUTLINER_OT_unhide_all(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Unhide All"; - ot->idname = "OUTLINER_OT_unhide_all"; - ot->description = "Unhide all objects and collections"; + /* identifiers */ + ot->name = "Unhide All"; + ot->idname = "OUTLINER_OT_unhide_all"; + ot->description = "Unhide all objects and collections"; - /* api callbacks */ - ot->exec = outliner_unhide_all_exec; - ot->poll = outliner_view_layer_collections_editor_poll; + /* api callbacks */ + ot->exec = outliner_unhide_all_exec; + ot->poll = outliner_view_layer_collections_editor_poll; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /** @@ -1385,13 +1443,14 @@ void OUTLINER_OT_unhide_all(wmOperatorType *ot) */ void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - struct IDsSelectedData data = {{NULL}}; - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data); - LISTBASE_FOREACH (LinkData *, link, &data.selected_array) { - TreeElement *ten_selected = (TreeElement *)link->data; - Object *ob = (Object *)TREESTORE(ten_selected)->id; - BLI_addtail(objects, BLI_genericNodeN(ob)); - } - BLI_freelistN(&data.selected_array); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + struct IDsSelectedData data = {{NULL}}; + outliner_tree_traverse( + soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &data); + LISTBASE_FOREACH (LinkData *, link, &data.selected_array) { + TreeElement *ten_selected = (TreeElement *)link->data; + Object *ob = (Object *)TREESTORE(ten_selected)->id; + BLI_addtail(objects, BLI_genericNodeN(ob)); + } + BLI_freelistN(&data.selected_array); } diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c index 647fdeccb40..cff262698fa 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -69,948 +69,981 @@ /* ******************** Drop Target Find *********************** */ -static TreeElement *outliner_dropzone_element(TreeElement *te, const float fmval[2], const bool children) +static TreeElement *outliner_dropzone_element(TreeElement *te, + const float fmval[2], + const bool children) { - if ((fmval[1] > te->ys) && (fmval[1] < (te->ys + UI_UNIT_Y))) { - /* name and first icon */ - if ((fmval[0] > te->xs + UI_UNIT_X) && (fmval[0] < te->xend)) { - return te; - } - } - /* Not it. Let's look at its children. */ - if (children && (TREESTORE(te)->flag & TSE_CLOSED) == 0 && (te->subtree.first)) { - for (te = te->subtree.first; te; te = te->next) { - TreeElement *te_valid = outliner_dropzone_element(te, fmval, children); - if (te_valid) { - return te_valid; - } - } - } - return NULL; + if ((fmval[1] > te->ys) && (fmval[1] < (te->ys + UI_UNIT_Y))) { + /* name and first icon */ + if ((fmval[0] > te->xs + UI_UNIT_X) && (fmval[0] < te->xend)) { + return te; + } + } + /* Not it. Let's look at its children. */ + if (children && (TREESTORE(te)->flag & TSE_CLOSED) == 0 && (te->subtree.first)) { + for (te = te->subtree.first; te; te = te->next) { + TreeElement *te_valid = outliner_dropzone_element(te, fmval, children); + if (te_valid) { + return te_valid; + } + } + } + return NULL; } /* Find tree element to drop into. */ -static TreeElement *outliner_dropzone_find(const SpaceOutliner *soops, const float fmval[2], const bool children) +static TreeElement *outliner_dropzone_find(const SpaceOutliner *soops, + const float fmval[2], + const bool children) { - TreeElement *te; - - for (te = soops->tree.first; te; te = te->next) { - TreeElement *te_valid = outliner_dropzone_element(te, fmval, children); - if (te_valid) { - return te_valid; - } - } - return NULL; + TreeElement *te; + + for (te = soops->tree.first; te; te = te->next) { + TreeElement *te_valid = outliner_dropzone_element(te, fmval, children); + if (te_valid) { + return te_valid; + } + } + return NULL; } static TreeElement *outliner_drop_find(bContext *C, const wmEvent *event) { - ARegion *ar = CTX_wm_region(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - float fmval[2]; - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + ARegion *ar = CTX_wm_region(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + float fmval[2]; + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - return outliner_dropzone_find(soops, fmval, true); + return outliner_dropzone_find(soops, fmval, true); } static ID *outliner_ID_drop_find(bContext *C, const wmEvent *event, short idcode) { - TreeElement *te = outliner_drop_find(C, event); - TreeStoreElem *tselem = (te) ? TREESTORE(te) : NULL; - - if (te && te->idcode == idcode && tselem->type == 0) { - return tselem->id; - } - else { - return NULL; - } + TreeElement *te = outliner_drop_find(C, event); + TreeStoreElem *tselem = (te) ? TREESTORE(te) : NULL; + + if (te && te->idcode == idcode && tselem->type == 0) { + return tselem->id; + } + else { + return NULL; + } } /* Find tree element to drop into, with additional before and after reorder support. */ -static TreeElement *outliner_drop_insert_find( - bContext *C, const wmEvent *event, - TreeElementInsertType *r_insert_type) +static TreeElement *outliner_drop_insert_find(bContext *C, + const wmEvent *event, + TreeElementInsertType *r_insert_type) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - ARegion *ar = CTX_wm_region(C); - TreeElement *te_hovered; - float view_mval[2]; - - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]); - te_hovered = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]); - - if (te_hovered) { - /* mouse hovers an element (ignoring x-axis), now find out how to insert the dragged item exactly */ - const float margin = UI_UNIT_Y * (1.0f / 4); - - if (view_mval[1] < (te_hovered->ys + margin)) { - if (TSELEM_OPEN(TREESTORE(te_hovered), soops)) { - /* inserting after a open item means we insert into it, but as first child */ - if (BLI_listbase_is_empty(&te_hovered->subtree)) { - *r_insert_type = TE_INSERT_INTO; - return te_hovered; - } - else { - *r_insert_type = TE_INSERT_BEFORE; - return te_hovered->subtree.first; - } - } - else { - *r_insert_type = TE_INSERT_AFTER; - return te_hovered; - } - } - else if (view_mval[1] > (te_hovered->ys + (3 * margin))) { - *r_insert_type = TE_INSERT_BEFORE; - return te_hovered; - } - else { - *r_insert_type = TE_INSERT_INTO; - return te_hovered; - } - } - else { - /* mouse doesn't hover any item (ignoring x-axis), so it's either above list bounds or below. */ - TreeElement *first = soops->tree.first; - TreeElement *last = soops->tree.last; - - if (view_mval[1] < last->ys) { - *r_insert_type = TE_INSERT_AFTER; - return last; - } - else if (view_mval[1] > (first->ys + UI_UNIT_Y)) { - *r_insert_type = TE_INSERT_BEFORE; - return first; - } - else { - BLI_assert(0); - return NULL; - } - } + SpaceOutliner *soops = CTX_wm_space_outliner(C); + ARegion *ar = CTX_wm_region(C); + TreeElement *te_hovered; + float view_mval[2]; + + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]); + te_hovered = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]); + + if (te_hovered) { + /* mouse hovers an element (ignoring x-axis), now find out how to insert the dragged item exactly */ + const float margin = UI_UNIT_Y * (1.0f / 4); + + if (view_mval[1] < (te_hovered->ys + margin)) { + if (TSELEM_OPEN(TREESTORE(te_hovered), soops)) { + /* inserting after a open item means we insert into it, but as first child */ + if (BLI_listbase_is_empty(&te_hovered->subtree)) { + *r_insert_type = TE_INSERT_INTO; + return te_hovered; + } + else { + *r_insert_type = TE_INSERT_BEFORE; + return te_hovered->subtree.first; + } + } + else { + *r_insert_type = TE_INSERT_AFTER; + return te_hovered; + } + } + else if (view_mval[1] > (te_hovered->ys + (3 * margin))) { + *r_insert_type = TE_INSERT_BEFORE; + return te_hovered; + } + else { + *r_insert_type = TE_INSERT_INTO; + return te_hovered; + } + } + else { + /* mouse doesn't hover any item (ignoring x-axis), so it's either above list bounds or below. */ + TreeElement *first = soops->tree.first; + TreeElement *last = soops->tree.last; + + if (view_mval[1] < last->ys) { + *r_insert_type = TE_INSERT_AFTER; + return last; + } + else if (view_mval[1] > (first->ys + UI_UNIT_Y)) { + *r_insert_type = TE_INSERT_BEFORE; + return first; + } + else { + BLI_assert(0); + return NULL; + } + } } -static Collection *outliner_collection_from_tree_element_and_parents(TreeElement *te, TreeElement **r_te) +static Collection *outliner_collection_from_tree_element_and_parents(TreeElement *te, + TreeElement **r_te) { - while (te != NULL) { - Collection *collection = outliner_collection_from_tree_element(te); - if (collection) { - *r_te = te; - return collection; - } - te = te->parent; - } - return NULL; + while (te != NULL) { + Collection *collection = outliner_collection_from_tree_element(te); + if (collection) { + *r_te = te; + return collection; + } + te = te->parent; + } + return NULL; } -static TreeElement *outliner_drop_insert_collection_find( - bContext *C, const wmEvent *event, - TreeElementInsertType *r_insert_type) +static TreeElement *outliner_drop_insert_collection_find(bContext *C, + const wmEvent *event, + TreeElementInsertType *r_insert_type) { - TreeElement *te = outliner_drop_insert_find(C, event, r_insert_type); - if (!te) { - return NULL; - } - - TreeElement *collection_te; - Collection *collection = outliner_collection_from_tree_element_and_parents(te, &collection_te); - if (!collection) { - return NULL; - } - - if (collection_te != te) { - *r_insert_type = TE_INSERT_INTO; - } - - /* We can't insert before/after master collection. */ - if (collection->flag & COLLECTION_IS_MASTER) { - *r_insert_type = TE_INSERT_INTO; - } - - return collection_te; + TreeElement *te = outliner_drop_insert_find(C, event, r_insert_type); + if (!te) { + return NULL; + } + + TreeElement *collection_te; + Collection *collection = outliner_collection_from_tree_element_and_parents(te, &collection_te); + if (!collection) { + return NULL; + } + + if (collection_te != te) { + *r_insert_type = TE_INSERT_INTO; + } + + /* We can't insert before/after master collection. */ + if (collection->flag & COLLECTION_IS_MASTER) { + *r_insert_type = TE_INSERT_INTO; + } + + return collection_te; } /* ******************** Parent Drop Operator *********************** */ static bool parent_drop_allowed(SpaceOutliner *soops, TreeElement *te, Object *potential_child) { - TreeStoreElem *tselem = TREESTORE(te); - if (te->idcode != ID_OB || tselem->type != 0) { - return false; - } - - Object *potential_parent = (Object *)tselem->id; - - if (potential_parent == potential_child) { - return false; - } - if (BKE_object_is_child_recursive(potential_child, potential_parent)) { - return false; - } - if (potential_parent == potential_child->parent) { - return false; - } - - /* check that parent/child are both in the same scene */ - Scene *scene = (Scene *)outliner_search_back(soops, te, ID_SCE); - - /* currently outliner organized in a way that if there's no parent scene - * element for object it means that all displayed objects belong to - * active scene and parenting them is allowed (sergey) */ - if (scene) { - for (ViewLayer *view_layer = scene->view_layers.first; - view_layer; - view_layer = view_layer->next) - { - if (BKE_view_layer_base_find(view_layer, potential_child)) { - return true; - } - } - return false; - } - else { - return true; - } + TreeStoreElem *tselem = TREESTORE(te); + if (te->idcode != ID_OB || tselem->type != 0) { + return false; + } + + Object *potential_parent = (Object *)tselem->id; + + if (potential_parent == potential_child) { + return false; + } + if (BKE_object_is_child_recursive(potential_child, potential_parent)) { + return false; + } + if (potential_parent == potential_child->parent) { + return false; + } + + /* check that parent/child are both in the same scene */ + Scene *scene = (Scene *)outliner_search_back(soops, te, ID_SCE); + + /* currently outliner organized in a way that if there's no parent scene + * element for object it means that all displayed objects belong to + * active scene and parenting them is allowed (sergey) */ + if (scene) { + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; + view_layer = view_layer->next) { + if (BKE_view_layer_base_find(view_layer, potential_child)) { + return true; + } + } + return false; + } + else { + return true; + } } static bool allow_parenting_without_modifier_key(SpaceOutliner *soops) { - switch (soops->outlinevis) { - case SO_VIEW_LAYER: - return soops->filter & SO_FILTER_NO_COLLECTION; - case SO_SCENES: - return true; - default: - return false; - } + switch (soops->outlinevis) { + case SO_VIEW_LAYER: + return soops->filter & SO_FILTER_NO_COLLECTION; + case SO_SCENES: + return true; + default: + return false; + } } -static bool parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip)) +static bool parent_drop_poll(bContext *C, + wmDrag *drag, + const wmEvent *event, + const char **UNUSED(tooltip)) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - - bool changed = outliner_flag_set(&soops->tree, TSE_DRAG_ANY, false); - if (changed) { - ED_region_tag_redraw_no_rebuild(CTX_wm_region(C)); - } - - Object *potential_child = (Object *)WM_drag_ID(drag, ID_OB); - if (!potential_child) { - return false; - } - - if (!allow_parenting_without_modifier_key(soops)) { - if (!event->shift) { - return false; - } - } - - TreeElement *te = outliner_drop_find(C, event); - if (!te) { - return false; - } - - if (parent_drop_allowed(soops, te, potential_child)) { - TREESTORE(te)->flag |= TSE_DRAG_INTO; - ED_region_tag_redraw_no_rebuild(CTX_wm_region(C)); - return true; - } - - return false; + SpaceOutliner *soops = CTX_wm_space_outliner(C); + + bool changed = outliner_flag_set(&soops->tree, TSE_DRAG_ANY, false); + if (changed) { + ED_region_tag_redraw_no_rebuild(CTX_wm_region(C)); + } + + Object *potential_child = (Object *)WM_drag_ID(drag, ID_OB); + if (!potential_child) { + return false; + } + + if (!allow_parenting_without_modifier_key(soops)) { + if (!event->shift) { + return false; + } + } + + TreeElement *te = outliner_drop_find(C, event); + if (!te) { + return false; + } + + if (parent_drop_allowed(soops, te, potential_child)) { + TREESTORE(te)->flag |= TSE_DRAG_INTO; + ED_region_tag_redraw_no_rebuild(CTX_wm_region(C)); + return true; + } + + return false; } static int parent_drop_exec(bContext *C, wmOperator *op) { - Object *par = NULL, *ob = NULL; - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - int partype = -1; - char parname[MAX_NAME], childname[MAX_NAME]; - - partype = RNA_enum_get(op->ptr, "type"); - RNA_string_get(op->ptr, "parent", parname); - par = (Object *)BKE_libblock_find_name(bmain, ID_OB, parname); - RNA_string_get(op->ptr, "child", childname); - ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, childname); - - if (ID_IS_LINKED(ob)) { - BKE_report(op->reports, RPT_INFO, "Can't edit library linked object"); - return OPERATOR_CANCELLED; - } - - ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL); - - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); - - return OPERATOR_FINISHED; + Object *par = NULL, *ob = NULL; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + int partype = -1; + char parname[MAX_NAME], childname[MAX_NAME]; + + partype = RNA_enum_get(op->ptr, "type"); + RNA_string_get(op->ptr, "parent", parname); + par = (Object *)BKE_libblock_find_name(bmain, ID_OB, parname); + RNA_string_get(op->ptr, "child", childname); + ob = (Object *)BKE_libblock_find_name(bmain, ID_OB, childname); + + if (ID_IS_LINKED(ob)) { + BKE_report(op->reports, RPT_INFO, "Can't edit library linked object"); + return OPERATOR_CANCELLED; + } + + ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL); + + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); + + return OPERATOR_FINISHED; } static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - Main *bmain = CTX_data_main(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - TreeElement *te = outliner_drop_find(C, event); - TreeStoreElem *tselem = te ? TREESTORE(te) : NULL; - - if (!(te && te->idcode == ID_OB && tselem->type == 0)) { - return OPERATOR_CANCELLED; - } - - Object *par = (Object *)tselem->id; - Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB); - - if (ELEM(NULL, ob, par)) { - return OPERATOR_CANCELLED; - } - if (ob == par) { - return OPERATOR_CANCELLED; - } - if (ID_IS_LINKED(ob)) { - BKE_report(op->reports, RPT_INFO, "Can't edit library linked object"); - return OPERATOR_CANCELLED; - } - - char childname[MAX_NAME]; - char parname[MAX_NAME]; - STRNCPY(childname, ob->id.name + 2); - STRNCPY(parname, par->id.name + 2); - RNA_string_set(op->ptr, "child", childname); - RNA_string_set(op->ptr, "parent", parname); - - Scene *scene = (Scene *)outliner_search_back(soops, te, ID_SCE); - - if (scene == NULL) { - /* currently outlier organized in a way, that if there's no parent scene - * element for object it means that all displayed objects belong to - * active scene and parenting them is allowed (sergey) - */ - - scene = CTX_data_scene(C); - } - - if ((par->type != OB_ARMATURE) && (par->type != OB_CURVE) && (par->type != OB_LATTICE)) { - int partype = 0; - if (ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL)) { - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); - } - } - else { - /* Menu creation */ - wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_parent_drop", false); - uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Set Parent To"), ICON_NONE); - uiLayout *layout = UI_popup_menu_layout(pup); - PointerRNA ptr; - - /* Cannot use uiItemEnumO()... have multiple properties to set. */ - uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_OBJECT); - - /* par becomes parent, make the associated menus */ - if (par->type == OB_ARMATURE) { - uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_ARMATURE); - - uiItemFullO_ptr(layout, ot, IFACE_(" With Empty Groups"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_ARMATURE_NAME); - - uiItemFullO_ptr(layout, ot, IFACE_(" With Envelope Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_ARMATURE_ENVELOPE); - - uiItemFullO_ptr(layout, ot, IFACE_(" With Automatic Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_ARMATURE_AUTO); - - uiItemFullO_ptr(layout, ot, IFACE_("Bone"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_BONE); - } - else if (par->type == OB_CURVE) { - uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_CURVE); - - uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_FOLLOW); - - uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_PATH_CONST); - } - else if (par->type == OB_LATTICE) { - uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); - RNA_string_set(&ptr, "parent", parname); - RNA_string_set(&ptr, "child", childname); - RNA_enum_set(&ptr, "type", PAR_LATTICE); - } - - UI_popup_menu_end(C, pup); - - return OPERATOR_INTERFACE; - } - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + TreeElement *te = outliner_drop_find(C, event); + TreeStoreElem *tselem = te ? TREESTORE(te) : NULL; + + if (!(te && te->idcode == ID_OB && tselem->type == 0)) { + return OPERATOR_CANCELLED; + } + + Object *par = (Object *)tselem->id; + Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB); + + if (ELEM(NULL, ob, par)) { + return OPERATOR_CANCELLED; + } + if (ob == par) { + return OPERATOR_CANCELLED; + } + if (ID_IS_LINKED(ob)) { + BKE_report(op->reports, RPT_INFO, "Can't edit library linked object"); + return OPERATOR_CANCELLED; + } + + char childname[MAX_NAME]; + char parname[MAX_NAME]; + STRNCPY(childname, ob->id.name + 2); + STRNCPY(parname, par->id.name + 2); + RNA_string_set(op->ptr, "child", childname); + RNA_string_set(op->ptr, "parent", parname); + + Scene *scene = (Scene *)outliner_search_back(soops, te, ID_SCE); + + if (scene == NULL) { + /* currently outlier organized in a way, that if there's no parent scene + * element for object it means that all displayed objects belong to + * active scene and parenting them is allowed (sergey) + */ + + scene = CTX_data_scene(C); + } + + if ((par->type != OB_ARMATURE) && (par->type != OB_CURVE) && (par->type != OB_LATTICE)) { + int partype = 0; + if (ED_object_parent_set(op->reports, C, scene, ob, par, partype, false, false, NULL)) { + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); + } + } + else { + /* Menu creation */ + wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_parent_drop", false); + uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Set Parent To"), ICON_NONE); + uiLayout *layout = UI_popup_menu_layout(pup); + PointerRNA ptr; + + /* Cannot use uiItemEnumO()... have multiple properties to set. */ + uiItemFullO_ptr(layout, ot, IFACE_("Object"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_OBJECT); + + /* par becomes parent, make the associated menus */ + if (par->type == OB_ARMATURE) { + uiItemFullO_ptr(layout, ot, IFACE_("Armature Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_ARMATURE); + + uiItemFullO_ptr( + layout, ot, IFACE_(" With Empty Groups"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_ARMATURE_NAME); + + uiItemFullO_ptr( + layout, ot, IFACE_(" With Envelope Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_ARMATURE_ENVELOPE); + + uiItemFullO_ptr( + layout, ot, IFACE_(" With Automatic Weights"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_ARMATURE_AUTO); + + uiItemFullO_ptr(layout, ot, IFACE_("Bone"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_BONE); + } + else if (par->type == OB_CURVE) { + uiItemFullO_ptr(layout, ot, IFACE_("Curve Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_CURVE); + + uiItemFullO_ptr(layout, ot, IFACE_("Follow Path"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_FOLLOW); + + uiItemFullO_ptr(layout, ot, IFACE_("Path Constraint"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_PATH_CONST); + } + else if (par->type == OB_LATTICE) { + uiItemFullO_ptr(layout, ot, IFACE_("Lattice Deform"), 0, NULL, WM_OP_EXEC_DEFAULT, 0, &ptr); + RNA_string_set(&ptr, "parent", parname); + RNA_string_set(&ptr, "child", childname); + RNA_enum_set(&ptr, "type", PAR_LATTICE); + } + + UI_popup_menu_end(C, pup); + + return OPERATOR_INTERFACE; + } + + return OPERATOR_FINISHED; } void OUTLINER_OT_parent_drop(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Drop to Set Parent"; - ot->description = "Drag to parent in Outliner"; - ot->idname = "OUTLINER_OT_parent_drop"; + /* identifiers */ + ot->name = "Drop to Set Parent"; + ot->description = "Drag to parent in Outliner"; + ot->idname = "OUTLINER_OT_parent_drop"; - /* api callbacks */ - ot->invoke = parent_drop_invoke; - ot->exec = parent_drop_exec; + /* api callbacks */ + ot->invoke = parent_drop_invoke; + ot->exec = parent_drop_exec; - ot->poll = ED_operator_outliner_active; + ot->poll = ED_operator_outliner_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; - /* properties */ - RNA_def_string(ot->srna, "child", "Object", MAX_NAME, "Child", "Child Object"); - RNA_def_string(ot->srna, "parent", "Object", MAX_NAME, "Parent", "Parent Object"); - RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", ""); + /* properties */ + RNA_def_string(ot->srna, "child", "Object", MAX_NAME, "Child", "Child Object"); + RNA_def_string(ot->srna, "parent", "Object", MAX_NAME, "Parent", "Parent Object"); + RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", ""); } /* ******************** Parent Clear Operator *********************** */ -static bool parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip)) +static bool parent_clear_poll(bContext *C, + wmDrag *drag, + const wmEvent *event, + const char **UNUSED(tooltip)) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - - if (!allow_parenting_without_modifier_key(soops)) { - if (!event->shift) { - return false; - } - } - - Object *ob = (Object *)WM_drag_ID(drag, ID_OB); - if (!ob) { - return false; - } - if (!ob->parent) { - return false; - } - - TreeElement *te = outliner_drop_find(C, event); - if (te) { - TreeStoreElem *tselem = TREESTORE(te); - ID *id = tselem->id; - if (!id) { - return true; - } - - switch (GS(id->name)) { - case ID_OB: - return ELEM(tselem->type, TSE_MODIFIER_BASE, TSE_CONSTRAINT_BASE); - case ID_GR: - return event->shift; - default: - return true; - } - } - else { - return true; - } + SpaceOutliner *soops = CTX_wm_space_outliner(C); + + if (!allow_parenting_without_modifier_key(soops)) { + if (!event->shift) { + return false; + } + } + + Object *ob = (Object *)WM_drag_ID(drag, ID_OB); + if (!ob) { + return false; + } + if (!ob->parent) { + return false; + } + + TreeElement *te = outliner_drop_find(C, event); + if (te) { + TreeStoreElem *tselem = TREESTORE(te); + ID *id = tselem->id; + if (!id) { + return true; + } + + switch (GS(id->name)) { + case ID_OB: + return ELEM(tselem->type, TSE_MODIFIER_BASE, TSE_CONSTRAINT_BASE); + case ID_GR: + return event->shift; + default: + return true; + } + } + else { + return true; + } } static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { - Main *bmain = CTX_data_main(C); - Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB); + Main *bmain = CTX_data_main(C); + Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB); - if (ob == NULL) { - return OPERATOR_CANCELLED; - } + if (ob == NULL) { + return OPERATOR_CANCELLED; + } - ED_object_parent_clear(ob, 0); + ED_object_parent_clear(ob, 0); - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); - return OPERATOR_FINISHED; + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); + return OPERATOR_FINISHED; } void OUTLINER_OT_parent_clear(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Drop to Clear Parent"; - ot->description = "Drag to clear parent in Outliner"; - ot->idname = "OUTLINER_OT_parent_clear"; + /* identifiers */ + ot->name = "Drop to Clear Parent"; + ot->description = "Drag to clear parent in Outliner"; + ot->idname = "OUTLINER_OT_parent_clear"; - /* api callbacks */ - ot->invoke = parent_clear_invoke; + /* api callbacks */ + ot->invoke = parent_clear_invoke; - ot->poll = ED_operator_outliner_active; + ot->poll = ED_operator_outliner_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; } /* ******************** Scene Drop Operator *********************** */ -static bool scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip)) +static bool scene_drop_poll(bContext *C, + wmDrag *drag, + const wmEvent *event, + const char **UNUSED(tooltip)) { - /* Ensure item under cursor is valid drop target */ - Object *ob = (Object *)WM_drag_ID(drag, ID_OB); - return (ob && (outliner_ID_drop_find(C, event, ID_SCE) != NULL)); + /* Ensure item under cursor is valid drop target */ + Object *ob = (Object *)WM_drag_ID(drag, ID_OB); + return (ob && (outliner_ID_drop_find(C, event, ID_SCE) != NULL)); } static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { - Main *bmain = CTX_data_main(C); - Scene *scene = (Scene *)outliner_ID_drop_find(C, event, ID_SCE); - Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB); - - if (ELEM(NULL, ob, scene) || ID_IS_LINKED(scene)) { - return OPERATOR_CANCELLED; - } - - if (BKE_scene_has_object(scene, ob)) { - return OPERATOR_CANCELLED; - } - - Collection *collection; - if (scene != CTX_data_scene(C)) { - /* when linking to an inactive scene link to the master collection */ - collection = BKE_collection_master(scene); - } - else { - collection = CTX_data_collection(C); - } - - BKE_collection_object_add(bmain, collection, ob); - - for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { - Base *base = BKE_view_layer_base_find(view_layer, ob); - if (base) { - ED_object_base_select(base, BA_SELECT); - } - } - - DEG_relations_tag_update(bmain); - - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene); - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Scene *scene = (Scene *)outliner_ID_drop_find(C, event, ID_SCE); + Object *ob = (Object *)WM_drag_ID_from_event(event, ID_OB); + + if (ELEM(NULL, ob, scene) || ID_IS_LINKED(scene)) { + return OPERATOR_CANCELLED; + } + + if (BKE_scene_has_object(scene, ob)) { + return OPERATOR_CANCELLED; + } + + Collection *collection; + if (scene != CTX_data_scene(C)) { + /* when linking to an inactive scene link to the master collection */ + collection = BKE_collection_master(scene); + } + else { + collection = CTX_data_collection(C); + } + + BKE_collection_object_add(bmain, collection, ob); + + for (ViewLayer *view_layer = scene->view_layers.first; view_layer; + view_layer = view_layer->next) { + Base *base = BKE_view_layer_base_find(view_layer, ob); + if (base) { + ED_object_base_select(base, BA_SELECT); + } + } + + DEG_relations_tag_update(bmain); + + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_main_add_notifier(NC_SCENE | ND_OB_SELECT, scene); + + return OPERATOR_FINISHED; } void OUTLINER_OT_scene_drop(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Drop Object to Scene"; - ot->description = "Drag object to scene in Outliner"; - ot->idname = "OUTLINER_OT_scene_drop"; + /* identifiers */ + ot->name = "Drop Object to Scene"; + ot->description = "Drag object to scene in Outliner"; + ot->idname = "OUTLINER_OT_scene_drop"; - /* api callbacks */ - ot->invoke = scene_drop_invoke; + /* api callbacks */ + ot->invoke = scene_drop_invoke; - ot->poll = ED_operator_outliner_active; + ot->poll = ED_operator_outliner_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; } /* ******************** Material Drop Operator *********************** */ -static bool material_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **UNUSED(tooltip)) +static bool material_drop_poll(bContext *C, + wmDrag *drag, + const wmEvent *event, + const char **UNUSED(tooltip)) { - /* Ensure item under cursor is valid drop target */ - Material *ma = (Material *)WM_drag_ID(drag, ID_MA); - return (ma && (outliner_ID_drop_find(C, event, ID_OB) != NULL)); + /* Ensure item under cursor is valid drop target */ + Material *ma = (Material *)WM_drag_ID(drag, ID_MA); + return (ma && (outliner_ID_drop_find(C, event, ID_OB) != NULL)); } static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { - Main *bmain = CTX_data_main(C); - Object *ob = (Object *)outliner_ID_drop_find(C, event, ID_OB); - Material *ma = (Material *)WM_drag_ID_from_event(event, ID_MA); + Main *bmain = CTX_data_main(C); + Object *ob = (Object *)outliner_ID_drop_find(C, event, ID_OB); + Material *ma = (Material *)WM_drag_ID_from_event(event, ID_MA); - if (ELEM(NULL, ob, ma)) { - return OPERATOR_CANCELLED; - } + if (ELEM(NULL, ob, ma)) { + return OPERATOR_CANCELLED; + } - /* only drop grease pencil material on grease pencil objects */ - if ((ma->gp_style != NULL) && (ob->type != OB_GPENCIL)) { - return OPERATOR_CANCELLED; - } + /* only drop grease pencil material on grease pencil objects */ + if ((ma->gp_style != NULL) && (ob->type != OB_GPENCIL)) { + return OPERATOR_CANCELLED; + } - assign_material(bmain, ob, ma, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF); + assign_material(bmain, ob, ma, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C)); - WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C)); + WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_material_drop(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Drop Material on Object"; - ot->description = "Drag material to object in Outliner"; - ot->idname = "OUTLINER_OT_material_drop"; + /* identifiers */ + ot->name = "Drop Material on Object"; + ot->description = "Drag material to object in Outliner"; + ot->idname = "OUTLINER_OT_material_drop"; - /* api callbacks */ - ot->invoke = material_drop_invoke; + /* api callbacks */ + ot->invoke = material_drop_invoke; - ot->poll = ED_operator_outliner_active; + ot->poll = ED_operator_outliner_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; } /* ******************** Collection Drop Operator *********************** */ typedef struct CollectionDrop { - Collection *from; - Collection *to; + Collection *from; + Collection *to; - TreeElement *te; - TreeElementInsertType insert_type; + TreeElement *te; + TreeElementInsertType insert_type; } CollectionDrop; static Collection *collection_parent_from_ID(ID *id) { - /* Can't change linked parent collections. */ - if (!id || ID_IS_LINKED(id)) { - return NULL; - } - - /* Also support dropping into/from scene collection. */ - if (GS(id->name) == ID_SCE) { - return ((Scene *)id)->master_collection; - } - else if (GS(id->name) == ID_GR) { - return (Collection *)id; - } - - return NULL; + /* Can't change linked parent collections. */ + if (!id || ID_IS_LINKED(id)) { + return NULL; + } + + /* Also support dropping into/from scene collection. */ + if (GS(id->name) == ID_SCE) { + return ((Scene *)id)->master_collection; + } + else if (GS(id->name) == ID_GR) { + return (Collection *)id; + } + + return NULL; } -static bool collection_drop_init(bContext *C, wmDrag *drag, const wmEvent *event, CollectionDrop *data) +static bool collection_drop_init(bContext *C, + wmDrag *drag, + const wmEvent *event, + CollectionDrop *data) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - - /* Get collection to drop into. */ - TreeElementInsertType insert_type; - TreeElement *te = outliner_drop_insert_collection_find(C, event, &insert_type); - if (!te) { - return false; - } - - Collection *to_collection = outliner_collection_from_tree_element(te); - if (ID_IS_LINKED(to_collection)) { - return false; - } - - /* Get drag datablocks. */ - if (drag->type != WM_DRAG_ID) { - return false; - } - - wmDragID *drag_id = drag->ids.first; - if (drag_id == NULL) { - return false; - } - - ID *id = drag_id->id; - if (!(id && ELEM(GS(id->name), ID_GR, ID_OB))) { - return false; - } - - /* Get collection to drag out of. */ - ID *parent = drag_id->from_parent; - Collection *from_collection = collection_parent_from_ID(parent); - if (event->ctrl || soops->outlinevis == SO_SCENES) { - from_collection = NULL; - } - - /* Get collections. */ - if (GS(id->name) == ID_GR) { - if (id == &to_collection->id) { - return false; - } - } - else { - insert_type = TE_INSERT_INTO; - } - - data->from = from_collection; - data->to = to_collection; - data->te = te; - data->insert_type = insert_type; - - return true; + SpaceOutliner *soops = CTX_wm_space_outliner(C); + + /* Get collection to drop into. */ + TreeElementInsertType insert_type; + TreeElement *te = outliner_drop_insert_collection_find(C, event, &insert_type); + if (!te) { + return false; + } + + Collection *to_collection = outliner_collection_from_tree_element(te); + if (ID_IS_LINKED(to_collection)) { + return false; + } + + /* Get drag datablocks. */ + if (drag->type != WM_DRAG_ID) { + return false; + } + + wmDragID *drag_id = drag->ids.first; + if (drag_id == NULL) { + return false; + } + + ID *id = drag_id->id; + if (!(id && ELEM(GS(id->name), ID_GR, ID_OB))) { + return false; + } + + /* Get collection to drag out of. */ + ID *parent = drag_id->from_parent; + Collection *from_collection = collection_parent_from_ID(parent); + if (event->ctrl || soops->outlinevis == SO_SCENES) { + from_collection = NULL; + } + + /* Get collections. */ + if (GS(id->name) == ID_GR) { + if (id == &to_collection->id) { + return false; + } + } + else { + insert_type = TE_INSERT_INTO; + } + + data->from = from_collection; + data->to = to_collection; + data->te = te; + data->insert_type = insert_type; + + return true; } -static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event, const char **tooltip) +static bool collection_drop_poll(bContext *C, + wmDrag *drag, + const wmEvent *event, + const char **tooltip) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - ARegion *ar = CTX_wm_region(C); - bool changed = outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false); - - CollectionDrop data; - if (!event->shift && collection_drop_init(C, drag, event, &data)) { - TreeElement *te = data.te; - TreeStoreElem *tselem = TREESTORE(te); - if (!data.from || event->ctrl) { - tselem->flag |= TSE_DRAG_INTO; - changed = true; - *tooltip = IFACE_("Link inside Collection"); - } - else { - switch (data.insert_type) { - case TE_INSERT_BEFORE: - tselem->flag |= TSE_DRAG_BEFORE; - changed = true; - if (te->prev && outliner_is_collection_tree_element(te->prev)) { - *tooltip = TIP_("Move between collections"); - } - else { - *tooltip = TIP_("Move before collection"); - } - break; - case TE_INSERT_AFTER: - tselem->flag |= TSE_DRAG_AFTER; - changed = true; - if (te->next && outliner_is_collection_tree_element(te->next)) { - *tooltip = TIP_("Move between collections"); - } - else { - *tooltip = TIP_("Move after collection"); - } - break; - case TE_INSERT_INTO: - tselem->flag |= TSE_DRAG_INTO; - changed = true; - *tooltip = TIP_("Move inside collection (Ctrl to link, Shift to parent)"); - break; - } - } - if (changed) { - ED_region_tag_redraw_no_rebuild(ar); - } - return true; - } - else { - if (changed) { - ED_region_tag_redraw_no_rebuild(ar); - } - return false; - } + SpaceOutliner *soops = CTX_wm_space_outliner(C); + ARegion *ar = CTX_wm_region(C); + bool changed = outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false); + + CollectionDrop data; + if (!event->shift && collection_drop_init(C, drag, event, &data)) { + TreeElement *te = data.te; + TreeStoreElem *tselem = TREESTORE(te); + if (!data.from || event->ctrl) { + tselem->flag |= TSE_DRAG_INTO; + changed = true; + *tooltip = IFACE_("Link inside Collection"); + } + else { + switch (data.insert_type) { + case TE_INSERT_BEFORE: + tselem->flag |= TSE_DRAG_BEFORE; + changed = true; + if (te->prev && outliner_is_collection_tree_element(te->prev)) { + *tooltip = TIP_("Move between collections"); + } + else { + *tooltip = TIP_("Move before collection"); + } + break; + case TE_INSERT_AFTER: + tselem->flag |= TSE_DRAG_AFTER; + changed = true; + if (te->next && outliner_is_collection_tree_element(te->next)) { + *tooltip = TIP_("Move between collections"); + } + else { + *tooltip = TIP_("Move after collection"); + } + break; + case TE_INSERT_INTO: + tselem->flag |= TSE_DRAG_INTO; + changed = true; + *tooltip = TIP_("Move inside collection (Ctrl to link, Shift to parent)"); + break; + } + } + if (changed) { + ED_region_tag_redraw_no_rebuild(ar); + } + return true; + } + else { + if (changed) { + ED_region_tag_redraw_no_rebuild(ar); + } + return false; + } } static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - - if (event->custom != EVT_DATA_DRAGDROP) { - return OPERATOR_CANCELLED; - } - - ListBase *lb = event->customdata; - wmDrag *drag = lb->first; - - CollectionDrop data; - if (!collection_drop_init(C, drag, event, &data)) { - return OPERATOR_CANCELLED; - } - - /* Before/after insert handling. */ - Collection *relative = NULL; - bool relative_after = false; - - if (ELEM(data.insert_type, TE_INSERT_BEFORE, TE_INSERT_AFTER)) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - - relative = data.to; - relative_after = (data.insert_type == TE_INSERT_AFTER); - - TreeElement *parent_te = outliner_find_parent_element(&soops->tree, NULL, data.te); - data.to = (parent_te) ? outliner_collection_from_tree_element(parent_te) : NULL; - } - - if (!data.to) { - return OPERATOR_CANCELLED; - } - - if (BKE_collection_is_empty(data.to)) { - TREESTORE(data.te)->flag &= ~TSE_CLOSED; - } - - for (wmDragID *drag_id = drag->ids.first; drag_id; drag_id = drag_id->next) { - /* Ctrl enables linking, so we don't need a from collection then. */ - Collection *from = (event->ctrl) ? NULL : collection_parent_from_ID(drag_id->from_parent); - - if (GS(drag_id->id->name) == ID_OB) { - /* Move/link object into collection. */ - Object *object = (Object *)drag_id->id; - - if (from) { - BKE_collection_object_move(bmain, scene, data.to, from, object); - } - else { - BKE_collection_object_add(bmain, data.to, object); - } - } - else if (GS(drag_id->id->name) == ID_GR) { - /* Move/link collection into collection. */ - Collection *collection = (Collection *)drag_id->id; - - if (collection != from) { - BKE_collection_move(bmain, data.to, from, relative, relative_after, collection); - } - } - - if (from) { - DEG_id_tag_update(&from->id, ID_RECALC_COPY_ON_WRITE); - } - } - - /* Update dependency graph. */ - DEG_id_tag_update(&data.to->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); - - return OPERATOR_FINISHED; + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + + if (event->custom != EVT_DATA_DRAGDROP) { + return OPERATOR_CANCELLED; + } + + ListBase *lb = event->customdata; + wmDrag *drag = lb->first; + + CollectionDrop data; + if (!collection_drop_init(C, drag, event, &data)) { + return OPERATOR_CANCELLED; + } + + /* Before/after insert handling. */ + Collection *relative = NULL; + bool relative_after = false; + + if (ELEM(data.insert_type, TE_INSERT_BEFORE, TE_INSERT_AFTER)) { + SpaceOutliner *soops = CTX_wm_space_outliner(C); + + relative = data.to; + relative_after = (data.insert_type == TE_INSERT_AFTER); + + TreeElement *parent_te = outliner_find_parent_element(&soops->tree, NULL, data.te); + data.to = (parent_te) ? outliner_collection_from_tree_element(parent_te) : NULL; + } + + if (!data.to) { + return OPERATOR_CANCELLED; + } + + if (BKE_collection_is_empty(data.to)) { + TREESTORE(data.te)->flag &= ~TSE_CLOSED; + } + + for (wmDragID *drag_id = drag->ids.first; drag_id; drag_id = drag_id->next) { + /* Ctrl enables linking, so we don't need a from collection then. */ + Collection *from = (event->ctrl) ? NULL : collection_parent_from_ID(drag_id->from_parent); + + if (GS(drag_id->id->name) == ID_OB) { + /* Move/link object into collection. */ + Object *object = (Object *)drag_id->id; + + if (from) { + BKE_collection_object_move(bmain, scene, data.to, from, object); + } + else { + BKE_collection_object_add(bmain, data.to, object); + } + } + else if (GS(drag_id->id->name) == ID_GR) { + /* Move/link collection into collection. */ + Collection *collection = (Collection *)drag_id->id; + + if (collection != from) { + BKE_collection_move(bmain, data.to, from, relative, relative_after, collection); + } + } + + if (from) { + DEG_id_tag_update(&from->id, ID_RECALC_COPY_ON_WRITE); + } + } + + /* Update dependency graph. */ + DEG_id_tag_update(&data.to->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + + return OPERATOR_FINISHED; } void OUTLINER_OT_collection_drop(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Move to Collection"; - ot->description = "Drag to move to collection in Outliner"; - ot->idname = "OUTLINER_OT_collection_drop"; + /* identifiers */ + ot->name = "Move to Collection"; + ot->description = "Drag to move to collection in Outliner"; + ot->idname = "OUTLINER_OT_collection_drop"; - /* api callbacks */ - ot->invoke = collection_drop_invoke; - ot->poll = ED_operator_outliner_active; + /* api callbacks */ + ot->invoke = collection_drop_invoke; + ot->poll = ED_operator_outliner_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; } /* ********************* Outliner Drag Operator ******************** */ -static TreeElement *outliner_item_drag_element_find(SpaceOutliner *soops, ARegion *ar, const wmEvent *event) +static TreeElement *outliner_item_drag_element_find(SpaceOutliner *soops, + ARegion *ar, + const wmEvent *event) { - /* note: using EVT_TWEAK_ events to trigger dragging is fine, - * it sends coordinates from where dragging was started */ - const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]); - return outliner_find_item_at_y(soops, &soops->tree, my); + /* note: using EVT_TWEAK_ events to trigger dragging is fine, + * it sends coordinates from where dragging was started */ + const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]); + return outliner_find_item_at_y(soops, &soops->tree, my); } -static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) +static int outliner_item_drag_drop_invoke(bContext *C, + wmOperator *UNUSED(op), + const wmEvent *event) { - ARegion *ar = CTX_wm_region(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - TreeElement *te = outliner_item_drag_element_find(soops, ar, event); - - if (!te) { - return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); - } - - TreeElementIcon data = tree_element_get_icon(TREESTORE(te), te); - if (!data.drag_id) { - return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); - } - - wmDrag *drag = WM_event_start_drag(C, data.icon, WM_DRAG_ID, NULL, 0.0, WM_DRAG_NOP); - - if (ELEM(GS(data.drag_id->name), ID_OB, ID_GR)) { - /* For collections and objects we cheat and drag all selected. */ - - /* Only drag element under mouse if it was not selected before. */ - if ((TREESTORE(te)->flag & TSE_SELECTED) == 0) { - outliner_flag_set(&soops->tree, TSE_SELECTED, 0); - TREESTORE(te)->flag |= TSE_SELECTED; - } - - /* Gather all selected elements. */ - struct IDsSelectedData selected = { - .selected_array = {NULL, NULL}, - }; - - if (GS(data.drag_id->name) == ID_OB) { - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &selected); - } - else { - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_collections, &selected); - } - - LISTBASE_FOREACH (LinkData *, link, &selected.selected_array) { - TreeElement *te_selected = (TreeElement *)link->data; - ID *id; - - if (GS(data.drag_id->name) == ID_OB) { - id = TREESTORE(te_selected)->id; - } - else { - /* Keep collection hierarchies intact when dragging. */ - bool parent_selected = false; - for (TreeElement *te_parent = te_selected->parent; te_parent; te_parent = te_parent->parent) { - if (outliner_is_collection_tree_element(te_parent)) { - if (TREESTORE(te_parent)->flag & TSE_SELECTED) { - parent_selected = true; - break; - } - } - } - - if (parent_selected) { - continue; - } - - id = &outliner_collection_from_tree_element(te_selected)->id; - } - - /* Find parent collection. */ - Collection *parent = NULL; - - if (te_selected->parent) { - for (TreeElement *te_parent = te_selected->parent; te_parent; te_parent = te_parent->parent) { - if (outliner_is_collection_tree_element(te_parent)) { - parent = outliner_collection_from_tree_element(te_parent); - break; - } - } - } - else { - Scene *scene = CTX_data_scene(C); - parent = BKE_collection_master(scene); - } - - WM_drag_add_ID(drag, id, &parent->id); - } - - BLI_freelistN(&selected.selected_array); - } - else { - /* Add single ID. */ - WM_drag_add_ID(drag, data.drag_id, data.drag_parent); - } - - return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH); + ARegion *ar = CTX_wm_region(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + TreeElement *te = outliner_item_drag_element_find(soops, ar, event); + + if (!te) { + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + TreeElementIcon data = tree_element_get_icon(TREESTORE(te), te); + if (!data.drag_id) { + return (OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH); + } + + wmDrag *drag = WM_event_start_drag(C, data.icon, WM_DRAG_ID, NULL, 0.0, WM_DRAG_NOP); + + if (ELEM(GS(data.drag_id->name), ID_OB, ID_GR)) { + /* For collections and objects we cheat and drag all selected. */ + + /* Only drag element under mouse if it was not selected before. */ + if ((TREESTORE(te)->flag & TSE_SELECTED) == 0) { + outliner_flag_set(&soops->tree, TSE_SELECTED, 0); + TREESTORE(te)->flag |= TSE_SELECTED; + } + + /* Gather all selected elements. */ + struct IDsSelectedData selected = { + .selected_array = {NULL, NULL}, + }; + + if (GS(data.drag_id->name) == ID_OB) { + outliner_tree_traverse( + soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_objects, &selected); + } + else { + outliner_tree_traverse( + soops, &soops->tree, 0, TSE_SELECTED, outliner_find_selected_collections, &selected); + } + + LISTBASE_FOREACH (LinkData *, link, &selected.selected_array) { + TreeElement *te_selected = (TreeElement *)link->data; + ID *id; + + if (GS(data.drag_id->name) == ID_OB) { + id = TREESTORE(te_selected)->id; + } + else { + /* Keep collection hierarchies intact when dragging. */ + bool parent_selected = false; + for (TreeElement *te_parent = te_selected->parent; te_parent; + te_parent = te_parent->parent) { + if (outliner_is_collection_tree_element(te_parent)) { + if (TREESTORE(te_parent)->flag & TSE_SELECTED) { + parent_selected = true; + break; + } + } + } + + if (parent_selected) { + continue; + } + + id = &outliner_collection_from_tree_element(te_selected)->id; + } + + /* Find parent collection. */ + Collection *parent = NULL; + + if (te_selected->parent) { + for (TreeElement *te_parent = te_selected->parent; te_parent; + te_parent = te_parent->parent) { + if (outliner_is_collection_tree_element(te_parent)) { + parent = outliner_collection_from_tree_element(te_parent); + break; + } + } + } + else { + Scene *scene = CTX_data_scene(C); + parent = BKE_collection_master(scene); + } + + WM_drag_add_ID(drag, id, &parent->id); + } + + BLI_freelistN(&selected.selected_array); + } + else { + /* Add single ID. */ + WM_drag_add_ID(drag, data.drag_id, data.drag_parent); + } + + return (OPERATOR_FINISHED | OPERATOR_PASS_THROUGH); } /* Outliner drag and drop. This operator mostly exists to support dragging @@ -1019,12 +1052,12 @@ static int outliner_item_drag_drop_invoke(bContext *C, wmOperator *UNUSED(op), c void OUTLINER_OT_item_drag_drop(wmOperatorType *ot) { - ot->name = "Drag and Drop"; - ot->idname = "OUTLINER_OT_item_drag_drop"; - ot->description = "Drag and drop element to another place"; + ot->name = "Drag and Drop"; + ot->idname = "OUTLINER_OT_item_drag_drop"; + ot->description = "Drag and drop element to another place"; - ot->invoke = outliner_item_drag_drop_invoke; - ot->poll = ED_operator_outliner_active; + ot->invoke = outliner_item_drag_drop_invoke; + ot->poll = ED_operator_outliner_active; } /* *************************** Drop Boxes ************************** */ @@ -1032,11 +1065,11 @@ void OUTLINER_OT_item_drag_drop(wmOperatorType *ot) /* region dropbox definition */ void outliner_dropboxes(void) { - ListBase *lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW); + ListBase *lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW); - WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", parent_drop_poll, NULL); - WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", parent_clear_poll, NULL); - WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", scene_drop_poll, NULL); - WM_dropbox_add(lb, "OUTLINER_OT_material_drop", material_drop_poll, NULL); - WM_dropbox_add(lb, "OUTLINER_OT_collection_drop", collection_drop_poll, NULL); + WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", parent_drop_poll, NULL); + WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", parent_clear_poll, NULL); + WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", scene_drop_poll, NULL); + WM_dropbox_add(lb, "OUTLINER_OT_material_drop", material_drop_poll, NULL); + WM_dropbox_add(lb, "OUTLINER_OT_collection_drop", collection_drop_poll, NULL); } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index ff0b9d8a55f..2d33c5db49d 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -84,56 +84,56 @@ static void outliner_height(SpaceOutliner *soops, ListBase *lb, int *h) { - TreeElement *te = lb->first; - while (te) { - TreeStoreElem *tselem = TREESTORE(te); - if (TSELEM_OPEN(tselem, soops)) { - outliner_height(soops, &te->subtree, h); - } - (*h) += UI_UNIT_Y; - te = te->next; - } + TreeElement *te = lb->first; + while (te) { + TreeStoreElem *tselem = TREESTORE(te); + if (TSELEM_OPEN(tselem, soops)) { + outliner_height(soops, &te->subtree, h); + } + (*h) += UI_UNIT_Y; + te = te->next; + } } #if 0 // XXX this is currently disabled until te->xend is set correctly static void outliner_width(SpaceOutliner *soops, ListBase *lb, int *w) { - TreeElement *te = lb->first; - while (te) { -// TreeStoreElem *tselem = TREESTORE(te); - - // XXX fixme... te->xend is not set yet - if (!TSELEM_OPEN(tselem, soops)) { - if (te->xend > *w) - *w = te->xend; - } - outliner_width(soops, &te->subtree, w); - te = te->next; - } + TreeElement *te = lb->first; + while (te) { +// TreeStoreElem *tselem = TREESTORE(te); + + // XXX fixme... te->xend is not set yet + if (!TSELEM_OPEN(tselem, soops)) { + if (te->xend > *w) + *w = te->xend; + } + outliner_width(soops, &te->subtree, w); + te = te->next; + } } #endif static void outliner_rna_width(SpaceOutliner *soops, ListBase *lb, int *w, int startx) { - TreeElement *te = lb->first; - while (te) { - TreeStoreElem *tselem = TREESTORE(te); - // XXX fixme... (currently, we're using a fixed length of 100)! + TreeElement *te = lb->first; + while (te) { + TreeStoreElem *tselem = TREESTORE(te); + // XXX fixme... (currently, we're using a fixed length of 100)! #if 0 - if (te->xend) { - if (te->xend > *w) - *w = te->xend; - } + if (te->xend) { + if (te->xend > *w) + *w = te->xend; + } #endif - if (startx + 100 > *w) { - *w = startx + 100; - } - - if (TSELEM_OPEN(tselem, soops)) { - outliner_rna_width(soops, &te->subtree, w, startx + UI_UNIT_X); - } - te = te->next; - } + if (startx + 100 > *w) { + *w = startx + 100; + } + + if (TSELEM_OPEN(tselem, soops)) { + outliner_rna_width(soops, &te->subtree, w, startx + UI_UNIT_X); + } + te = te->next; + } } /** @@ -141,830 +141,1092 @@ static void outliner_rna_width(SpaceOutliner *soops, ListBase *lb, int *w, int s */ static bool is_object_data_in_editmode(const ID *id, const Object *obact) { - const short id_type = GS(id->name); - return ( - (obact && (obact->mode & OB_MODE_EDIT)) && - (id && OB_DATA_SUPPORT_EDITMODE(id_type)) && - (GS(((ID *)obact->data)->name) == id_type) && - BKE_object_data_is_in_editmode(id) - ); + const short id_type = GS(id->name); + return ((obact && (obact->mode & OB_MODE_EDIT)) && (id && OB_DATA_SUPPORT_EDITMODE(id_type)) && + (GS(((ID *)obact->data)->name) == id_type) && BKE_object_data_is_in_editmode(id)); } /* ****************************************************** */ -static void restrictbutton_recursive_ebone(bContext *C, EditBone *ebone_parent, int flag, bool set_flag) +static void restrictbutton_recursive_ebone(bContext *C, + EditBone *ebone_parent, + int flag, + bool set_flag) { - Object *obedit = CTX_data_edit_object(C); - bArmature *arm = obedit->data; - EditBone *ebone; - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { - if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) { - if (set_flag) { - ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); - ebone->flag |= flag; - } - else { - ebone->flag &= ~flag; - } - } - } + Object *obedit = CTX_data_edit_object(C); + bArmature *arm = obedit->data; + EditBone *ebone; + + for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) { + if (set_flag) { + ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + ebone->flag |= flag; + } + else { + ebone->flag &= ~flag; + } + } + } } static void restrictbutton_recursive_bone(Bone *bone_parent, int flag, bool set_flag) { - Bone *bone; - for (bone = bone_parent->childbase.first; bone; bone = bone->next) { - if (set_flag) { - bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); - bone->flag |= flag; - } - else { - bone->flag &= ~flag; - } - restrictbutton_recursive_bone(bone, flag, set_flag); - } - + Bone *bone; + for (bone = bone_parent->childbase.first; bone; bone = bone->next) { + if (set_flag) { + bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + bone->flag |= flag; + } + else { + bone->flag &= ~flag; + } + restrictbutton_recursive_bone(bone, flag, set_flag); + } } static void restrictbutton_r_lay_cb(bContext *C, void *poin, void *UNUSED(poin2)) { - WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, poin); + WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, poin); } static void restrictbutton_bone_visibility_cb(bContext *C, void *UNUSED(poin), void *poin2) { - Bone *bone = (Bone *)poin2; - if (bone->flag & BONE_HIDDEN_P) { - bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } + Bone *bone = (Bone *)poin2; + if (bone->flag & BONE_HIDDEN_P) { + bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } - if (CTX_wm_window(C)->eventstate->ctrl) { - restrictbutton_recursive_bone(bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0); - } + if (CTX_wm_window(C)->eventstate->ctrl) { + restrictbutton_recursive_bone(bone, BONE_HIDDEN_P, (bone->flag & BONE_HIDDEN_P) != 0); + } - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); } static void restrictbutton_bone_select_cb(bContext *C, void *UNUSED(poin), void *poin2) { - Bone *bone = (Bone *)poin2; - if (bone->flag & BONE_UNSELECTABLE) { - bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } + Bone *bone = (Bone *)poin2; + if (bone->flag & BONE_UNSELECTABLE) { + bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } - if (CTX_wm_window(C)->eventstate->ctrl) { - restrictbutton_recursive_bone(bone, BONE_UNSELECTABLE, (bone->flag & BONE_UNSELECTABLE) != 0); - } + if (CTX_wm_window(C)->eventstate->ctrl) { + restrictbutton_recursive_bone(bone, BONE_UNSELECTABLE, (bone->flag & BONE_UNSELECTABLE) != 0); + } - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); } static void restrictbutton_ebone_select_cb(bContext *C, void *UNUSED(poin), void *poin2) { - EditBone *ebone = (EditBone *)poin2; + EditBone *ebone = (EditBone *)poin2; - if (ebone->flag & BONE_UNSELECTABLE) { - ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } + if (ebone->flag & BONE_UNSELECTABLE) { + ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } - if (CTX_wm_window(C)->eventstate->ctrl) { - restrictbutton_recursive_ebone(C, ebone, BONE_UNSELECTABLE, (ebone->flag & BONE_UNSELECTABLE) != 0); - } + if (CTX_wm_window(C)->eventstate->ctrl) { + restrictbutton_recursive_ebone( + C, ebone, BONE_UNSELECTABLE, (ebone->flag & BONE_UNSELECTABLE) != 0); + } - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); } static void restrictbutton_ebone_visibility_cb(bContext *C, void *UNUSED(poin), void *poin2) { - EditBone *ebone = (EditBone *)poin2; - if (ebone->flag & BONE_HIDDEN_A) { - ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - } + EditBone *ebone = (EditBone *)poin2; + if (ebone->flag & BONE_HIDDEN_A) { + ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } - if (CTX_wm_window(C)->eventstate->ctrl) { - restrictbutton_recursive_ebone(C, ebone, BONE_HIDDEN_A, (ebone->flag & BONE_HIDDEN_A) != 0); - } + if (CTX_wm_window(C)->eventstate->ctrl) { + restrictbutton_recursive_ebone(C, ebone, BONE_HIDDEN_A, (ebone->flag & BONE_HIDDEN_A) != 0); + } - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); } static void restrictbutton_gp_layer_flag_cb(bContext *C, void *poin, void *UNUSED(poin2)) { - ID *id = (ID *)poin; + ID *id = (ID *)poin; - DEG_id_tag_update(id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + DEG_id_tag_update(id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); } static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void *UNUSED(poin2)) { - ID *id = (ID *)poin; + ID *id = (ID *)poin; - BLI_assert(id != NULL); + BLI_assert(id != NULL); - if (id->flag & LIB_FAKEUSER) { - id_us_plus(id); - } - else { - id_us_min(id); - } + if (id->flag & LIB_FAKEUSER) { + id_us_plus(id); + } + else { + id_us_min(id); + } } static int base_pushed_state_cb(bContext *UNUSED(C), void *poin) { - Base *base = poin; - Object *ob = base->object; + Base *base = poin; + Object *ob = base->object; - const bool is_visible = ((base->flag & BASE_HIDDEN) == 0) && - ((ob->restrictflag & OB_RESTRICT_VIEW) == 0); - return !is_visible; + const bool is_visible = ((base->flag & BASE_HIDDEN) == 0) && + ((ob->restrictflag & OB_RESTRICT_VIEW) == 0); + return !is_visible; } static void hidebutton_base_flag_cb(bContext *C, void *poin, void *poin2) { - wmWindow *win = CTX_wm_window(C); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = poin; - Base *base = poin2; - Object *ob = base->object; - bool do_disable = (CTX_wm_window(C)->eventstate->alt != 0); - bool do_isolate = (win->eventstate->ctrl != 0) && !do_disable; - bool extend = (win->eventstate->shift != 0); - bool depsgraph_changed = false; - const bool is_linked = ID_IS_LINKED(ob); - - if (do_disable) { - if (!is_linked) { - ob->restrictflag |= OB_RESTRICT_VIEW; - depsgraph_changed = true; - } - } - else if (do_isolate) { - depsgraph_changed = (!is_linked) && ((ob->restrictflag & OB_RESTRICT_VIEW) != 0); - - if (!extend) { - /* Make only one base visible. */ - for (Base *other = view_layer->object_bases.first; other; other = other->next) { - other->flag |= BASE_HIDDEN; - } - - base->flag &= ~BASE_HIDDEN; - } - else { - /* Toggle visibility of one base. */ - base->flag ^= BASE_HIDDEN; - } - - if (!is_linked) { - ob->restrictflag &= ~OB_RESTRICT_VIEW; - } - } - else if (ob->restrictflag & OB_RESTRICT_VIEW) { - if (!is_linked) { - ob->restrictflag &= ~OB_RESTRICT_VIEW; - base->flag &= ~BASE_HIDDEN; - } - depsgraph_changed = true; - } - else { - base->flag ^= BASE_HIDDEN; - } - - if (depsgraph_changed) { - BKE_main_collection_sync_remap(bmain); - DEG_id_tag_update(&ob->id, LIB_TAG_COPIED_ON_WRITE); - DEG_relations_tag_update(bmain); - WM_main_add_notifier(NC_OBJECT | ND_DRAW, &ob->id); - } - - if (!do_disable) { - BKE_layer_collection_sync(scene, view_layer); - DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } + wmWindow *win = CTX_wm_window(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = poin; + Base *base = poin2; + Object *ob = base->object; + bool do_disable = (CTX_wm_window(C)->eventstate->alt != 0); + bool do_isolate = (win->eventstate->ctrl != 0) && !do_disable; + bool extend = (win->eventstate->shift != 0); + bool depsgraph_changed = false; + const bool is_linked = ID_IS_LINKED(ob); + + if (do_disable) { + if (!is_linked) { + ob->restrictflag |= OB_RESTRICT_VIEW; + depsgraph_changed = true; + } + } + else if (do_isolate) { + depsgraph_changed = (!is_linked) && ((ob->restrictflag & OB_RESTRICT_VIEW) != 0); + + if (!extend) { + /* Make only one base visible. */ + for (Base *other = view_layer->object_bases.first; other; other = other->next) { + other->flag |= BASE_HIDDEN; + } + + base->flag &= ~BASE_HIDDEN; + } + else { + /* Toggle visibility of one base. */ + base->flag ^= BASE_HIDDEN; + } + + if (!is_linked) { + ob->restrictflag &= ~OB_RESTRICT_VIEW; + } + } + else if (ob->restrictflag & OB_RESTRICT_VIEW) { + if (!is_linked) { + ob->restrictflag &= ~OB_RESTRICT_VIEW; + base->flag &= ~BASE_HIDDEN; + } + depsgraph_changed = true; + } + else { + base->flag ^= BASE_HIDDEN; + } + + if (depsgraph_changed) { + BKE_main_collection_sync_remap(bmain); + DEG_id_tag_update(&ob->id, LIB_TAG_COPIED_ON_WRITE); + DEG_relations_tag_update(bmain); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, &ob->id); + } + + if (!do_disable) { + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + } } static int layer_collection_pushed_state_cb(bContext *UNUSED(C), void *poin) { - LayerCollection *lc = poin; - Collection *collection = lc->collection; + LayerCollection *lc = poin; + Collection *collection = lc->collection; - const bool is_visible = ((lc->flag & LAYER_COLLECTION_RESTRICT_VIEW) == 0) && - ((collection->flag & COLLECTION_RESTRICT_VIEW) == 0); - return !is_visible; + const bool is_visible = ((lc->flag & LAYER_COLLECTION_RESTRICT_VIEW) == 0) && + ((collection->flag & COLLECTION_RESTRICT_VIEW) == 0); + return !is_visible; } static void hidebutton_layer_collection_flag_cb(bContext *C, void *poin, void *poin2) { - Main *bmain = CTX_data_main(C); - wmWindow *win = CTX_wm_window(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = poin; - LayerCollection *lc = poin2; - Collection *collection = lc->collection; - bool do_disable = (win->eventstate->alt != 0); - bool do_isolate = (win->eventstate->ctrl != 0) && !do_disable; - bool extend = (win->eventstate->shift != 0); - bool depsgraph_changed = false; - - if (do_disable) { - if (!ID_IS_LINKED(collection)) { - collection->flag |= COLLECTION_RESTRICT_VIEW; - depsgraph_changed = true; - } - } - else if (do_isolate) { - depsgraph_changed |= BKE_layer_collection_isolate(scene, view_layer, lc, extend); - } - else { - bool make_visible = ((lc->flag & LAYER_COLLECTION_RESTRICT_VIEW) != 0) || - ((collection->flag & COLLECTION_RESTRICT_VIEW) != 0); - depsgraph_changed |= BKE_layer_collection_set_visible(view_layer, lc, make_visible, extend); - } - - BKE_layer_collection_sync(scene, view_layer); - DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - - if (depsgraph_changed) { - BKE_main_collection_sync_remap(bmain); - DEG_relations_tag_update(bmain); - } - WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); + Main *bmain = CTX_data_main(C); + wmWindow *win = CTX_wm_window(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = poin; + LayerCollection *lc = poin2; + Collection *collection = lc->collection; + bool do_disable = (win->eventstate->alt != 0); + bool do_isolate = (win->eventstate->ctrl != 0) && !do_disable; + bool extend = (win->eventstate->shift != 0); + bool depsgraph_changed = false; + + if (do_disable) { + if (!ID_IS_LINKED(collection)) { + collection->flag |= COLLECTION_RESTRICT_VIEW; + depsgraph_changed = true; + } + } + else if (do_isolate) { + depsgraph_changed |= BKE_layer_collection_isolate(scene, view_layer, lc, extend); + } + else { + bool make_visible = ((lc->flag & LAYER_COLLECTION_RESTRICT_VIEW) != 0) || + ((collection->flag & COLLECTION_RESTRICT_VIEW) != 0); + depsgraph_changed |= BKE_layer_collection_set_visible(view_layer, lc, make_visible, extend); + } + + BKE_layer_collection_sync(scene, view_layer); + DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); + + if (depsgraph_changed) { + BKE_main_collection_sync_remap(bmain); + DEG_relations_tag_update(bmain); + } + WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); } static void namebutton_cb(bContext *C, void *tsep, char *oldname) { - Main *bmain = CTX_data_main(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - Object *obedit = CTX_data_edit_object(C); - BLI_mempool *ts = soops->treestore; - TreeStoreElem *tselem = tsep; - - if (ts && tselem) { - TreeElement *te = outliner_find_tree_element(&soops->tree, tselem); - - if (tselem->type == 0) { - BLI_libblock_ensure_unique_name(bmain, tselem->id->name); - - switch (GS(tselem->id->name)) { - case ID_MA: - WM_event_add_notifier(C, NC_MATERIAL, NULL); break; - case ID_TE: - WM_event_add_notifier(C, NC_TEXTURE, NULL); break; - case ID_IM: - WM_event_add_notifier(C, NC_IMAGE, NULL); break; - case ID_SCE: - WM_event_add_notifier(C, NC_SCENE, NULL); break; - case ID_OB: - { - Object *ob = (Object *)tselem->id; - if (ob->type == OB_MBALL) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - } - DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); - WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); break; - } - default: - WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); break; - } - /* Check the library target exists */ - if (te->idcode == ID_LI) { - Library *lib = (Library *)tselem->id; - char expanded[FILE_MAX]; - - BKE_library_filepath_set(bmain, lib, lib->name); - - BLI_strncpy(expanded, lib->name, sizeof(expanded)); - BLI_path_abs(expanded, BKE_main_blendfile_path(bmain)); - if (!BLI_exists(expanded)) { - BKE_reportf(CTX_wm_reports(C), RPT_ERROR, - "Library path '%s' does not exist, correct this before saving", expanded); - } - else if (lib->id.tag & LIB_TAG_MISSING) { - BKE_reportf(CTX_wm_reports(C), RPT_INFO, - "Library path '%s' is now valid, please reload the library", expanded); - lib->id.tag &= ~LIB_TAG_MISSING; - } - } - } - else { - switch (tselem->type) { - case TSE_DEFGROUP: - defgroup_unique_name(te->directdata, (Object *)tselem->id); // id = object - break; - case TSE_NLA_ACTION: - BLI_libblock_ensure_unique_name(bmain, tselem->id->name); - break; - case TSE_EBONE: - { - bArmature *arm = (bArmature *)tselem->id; - if (arm->edbo) { - EditBone *ebone = te->directdata; - char newname[sizeof(ebone->name)]; - - /* restore bone name */ - BLI_strncpy(newname, ebone->name, sizeof(ebone->name)); - BLI_strncpy(ebone->name, oldname, sizeof(ebone->name)); - ED_armature_bone_rename(bmain, obedit->data, oldname, newname); - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); - } - break; - } - - case TSE_BONE: - { - ViewLayer *view_layer = CTX_data_view_layer(C); - Scene *scene = CTX_data_scene(C); - bArmature *arm = (bArmature *)tselem->id; - Bone *bone = te->directdata; - char newname[sizeof(bone->name)]; - - /* always make current object active */ - tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, true); - - /* restore bone name */ - BLI_strncpy(newname, bone->name, sizeof(bone->name)); - BLI_strncpy(bone->name, oldname, sizeof(bone->name)); - ED_armature_bone_rename(bmain, arm, oldname, newname); - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); - break; - } - case TSE_POSE_CHANNEL: - { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob = (Object *)tselem->id; - bPoseChannel *pchan = te->directdata; - char newname[sizeof(pchan->name)]; - - /* always make current pose-bone active */ - tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, true); - - BLI_assert(ob->type == OB_ARMATURE); - - /* restore bone name */ - BLI_strncpy(newname, pchan->name, sizeof(pchan->name)); - BLI_strncpy(pchan->name, oldname, sizeof(pchan->name)); - ED_armature_bone_rename(bmain, ob->data, oldname, newname); - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); - break; - } - case TSE_POSEGRP: - { - Object *ob = (Object *)tselem->id; // id = object - bActionGroup *grp = te->directdata; - - BLI_uniquename(&ob->pose->agroups, grp, CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "Group"), '.', - offsetof(bActionGroup, name), sizeof(grp->name)); - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); - break; - } - case TSE_GP_LAYER: - { - bGPdata *gpd = (bGPdata *)tselem->id; /* id = GP Datablock */ - bGPDlayer *gpl = te->directdata; - - /* always make layer active */ - BKE_gpencil_layer_setactive(gpd, gpl); - - // XXX: name needs translation stuff - BLI_uniquename(&gpd->layers, gpl, "GP Layer", '.', - offsetof(bGPDlayer, info), sizeof(gpl->info)); - - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, gpd); - break; - } - case TSE_R_LAYER: - { - Scene *scene = (Scene *)tselem->id; - ViewLayer *view_layer = te->directdata; - - /* Restore old name. */ - char newname[sizeof(view_layer->name)]; - BLI_strncpy(newname, view_layer->name, sizeof(view_layer->name)); - BLI_strncpy(view_layer->name, oldname, sizeof(view_layer->name)); - - /* Rename, preserving animation and compositing data. */ - BKE_view_layer_rename(bmain, scene, view_layer, newname); - WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); - break; - } - case TSE_LAYER_COLLECTION: - { - BLI_libblock_ensure_unique_name(bmain, tselem->id->name); - WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); - break; - } - } - } - tselem->flag &= ~TSE_TEXTBUT; - } + Main *bmain = CTX_data_main(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + Object *obedit = CTX_data_edit_object(C); + BLI_mempool *ts = soops->treestore; + TreeStoreElem *tselem = tsep; + + if (ts && tselem) { + TreeElement *te = outliner_find_tree_element(&soops->tree, tselem); + + if (tselem->type == 0) { + BLI_libblock_ensure_unique_name(bmain, tselem->id->name); + + switch (GS(tselem->id->name)) { + case ID_MA: + WM_event_add_notifier(C, NC_MATERIAL, NULL); + break; + case ID_TE: + WM_event_add_notifier(C, NC_TEXTURE, NULL); + break; + case ID_IM: + WM_event_add_notifier(C, NC_IMAGE, NULL); + break; + case ID_SCE: + WM_event_add_notifier(C, NC_SCENE, NULL); + break; + case ID_OB: { + Object *ob = (Object *)tselem->id; + if (ob->type == OB_MBALL) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + } + DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); + break; + } + default: + WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); + break; + } + /* Check the library target exists */ + if (te->idcode == ID_LI) { + Library *lib = (Library *)tselem->id; + char expanded[FILE_MAX]; + + BKE_library_filepath_set(bmain, lib, lib->name); + + BLI_strncpy(expanded, lib->name, sizeof(expanded)); + BLI_path_abs(expanded, BKE_main_blendfile_path(bmain)); + if (!BLI_exists(expanded)) { + BKE_reportf(CTX_wm_reports(C), + RPT_ERROR, + "Library path '%s' does not exist, correct this before saving", + expanded); + } + else if (lib->id.tag & LIB_TAG_MISSING) { + BKE_reportf(CTX_wm_reports(C), + RPT_INFO, + "Library path '%s' is now valid, please reload the library", + expanded); + lib->id.tag &= ~LIB_TAG_MISSING; + } + } + } + else { + switch (tselem->type) { + case TSE_DEFGROUP: + defgroup_unique_name(te->directdata, (Object *)tselem->id); // id = object + break; + case TSE_NLA_ACTION: + BLI_libblock_ensure_unique_name(bmain, tselem->id->name); + break; + case TSE_EBONE: { + bArmature *arm = (bArmature *)tselem->id; + if (arm->edbo) { + EditBone *ebone = te->directdata; + char newname[sizeof(ebone->name)]; + + /* restore bone name */ + BLI_strncpy(newname, ebone->name, sizeof(ebone->name)); + BLI_strncpy(ebone->name, oldname, sizeof(ebone->name)); + ED_armature_bone_rename(bmain, obedit->data, oldname, newname); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + } + break; + } + + case TSE_BONE: { + ViewLayer *view_layer = CTX_data_view_layer(C); + Scene *scene = CTX_data_scene(C); + bArmature *arm = (bArmature *)tselem->id; + Bone *bone = te->directdata; + char newname[sizeof(bone->name)]; + + /* always make current object active */ + tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, true); + + /* restore bone name */ + BLI_strncpy(newname, bone->name, sizeof(bone->name)); + BLI_strncpy(bone->name, oldname, sizeof(bone->name)); + ED_armature_bone_rename(bmain, arm, oldname, newname); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + break; + } + case TSE_POSE_CHANNEL: { + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = (Object *)tselem->id; + bPoseChannel *pchan = te->directdata; + char newname[sizeof(pchan->name)]; + + /* always make current pose-bone active */ + tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, true); + + BLI_assert(ob->type == OB_ARMATURE); + + /* restore bone name */ + BLI_strncpy(newname, pchan->name, sizeof(pchan->name)); + BLI_strncpy(pchan->name, oldname, sizeof(pchan->name)); + ED_armature_bone_rename(bmain, ob->data, oldname, newname); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + break; + } + case TSE_POSEGRP: { + Object *ob = (Object *)tselem->id; // id = object + bActionGroup *grp = te->directdata; + + BLI_uniquename(&ob->pose->agroups, + grp, + CTX_DATA_(BLT_I18NCONTEXT_ID_ACTION, "Group"), + '.', + offsetof(bActionGroup, name), + sizeof(grp->name)); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob); + break; + } + case TSE_GP_LAYER: { + bGPdata *gpd = (bGPdata *)tselem->id; /* id = GP Datablock */ + bGPDlayer *gpl = te->directdata; + + /* always make layer active */ + BKE_gpencil_layer_setactive(gpd, gpl); + + // XXX: name needs translation stuff + BLI_uniquename( + &gpd->layers, gpl, "GP Layer", '.', offsetof(bGPDlayer, info), sizeof(gpl->info)); + + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, gpd); + break; + } + case TSE_R_LAYER: { + Scene *scene = (Scene *)tselem->id; + ViewLayer *view_layer = te->directdata; + + /* Restore old name. */ + char newname[sizeof(view_layer->name)]; + BLI_strncpy(newname, view_layer->name, sizeof(view_layer->name)); + BLI_strncpy(view_layer->name, oldname, sizeof(view_layer->name)); + + /* Rename, preserving animation and compositing data. */ + BKE_view_layer_rename(bmain, scene, view_layer, newname); + WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); + break; + } + case TSE_LAYER_COLLECTION: { + BLI_libblock_ensure_unique_name(bmain, tselem->id->name); + WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); + break; + } + } + } + tselem->flag &= ~TSE_TEXTBUT; + } } -static void outliner_draw_restrictbuts( - uiBlock *block, Scene *scene, ViewLayer *view_layer, ARegion *ar, SpaceOutliner *soops, ListBase *lb) +static void outliner_draw_restrictbuts(uiBlock *block, + Scene *scene, + ViewLayer *view_layer, + ARegion *ar, + SpaceOutliner *soops, + ListBase *lb) { - /* Get RNA properties (once for speed). */ - static struct RestrictProperties { - bool initialized; - - PropertyRNA *object_hide_viewport, *object_hide_select, *object_hide_render; - PropertyRNA *collection_hide_viewport, *collection_hide_select, *collection_hide_render; - PropertyRNA *modifier_show_viewport, *modifier_show_render; - } props = {false}; - - if (!props.initialized) { - props.object_hide_viewport = RNA_struct_type_find_property(&RNA_Object, "hide_viewport"); - props.object_hide_select = RNA_struct_type_find_property(&RNA_Object, "hide_select"); - props.object_hide_render = RNA_struct_type_find_property(&RNA_Object, "hide_render"); - props.collection_hide_select = RNA_struct_type_find_property(&RNA_Collection, "hide_select"); - props.collection_hide_viewport = RNA_struct_type_find_property(&RNA_Collection, "hide_viewport"); - props.collection_hide_render = RNA_struct_type_find_property(&RNA_Collection, "hide_render"); - props.modifier_show_viewport = RNA_struct_type_find_property(&RNA_Modifier, "show_viewport"); - props.modifier_show_render = RNA_struct_type_find_property(&RNA_Modifier, "show_render"); - - props.initialized = true; - } - - /* Create buttons. */ - uiBut *bt; - - for (TreeElement *te = lb->first; te; te = te->next) { - TreeStoreElem *tselem = TREESTORE(te); - if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) { - if (tselem->type == TSE_R_LAYER && (soops->outlinevis == SO_SCENES)) { - /* View layer render toggle. */ - ViewLayer *layer = te->directdata; - - bt = uiDefIconButBitS( - block, UI_BTYPE_ICON_TOGGLE_N, VIEW_LAYER_RENDER, 0, ICON_RESTRICT_RENDER_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &layer->flag, 0, 0, 0, 0, TIP_("Use view layer for rendering")); - UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); - } - else if (tselem->type == 0 && te->idcode == ID_OB) { - PointerRNA ptr; - Object *ob = (Object *)tselem->id; - RNA_pointer_create(&ob->id, &RNA_Object, ob, &ptr); - Base *base = BKE_view_layer_base_find(view_layer, ob); - - if (base) { - int icon = ICON_RESTRICT_VIEW_ON; - if ((ob->restrictflag & OB_RESTRICT_VIEW) == 0) { - icon = (base->flag & BASE_HIDDEN) != 0 ? - ICON_HIDE_ON : - ICON_HIDE_OFF; - } - bt = uiDefIconBut( - block, UI_BTYPE_ICON_TOGGLE, 0, icon, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y, - NULL, 0, 0, 0, 0, - TIP_("Hide object in viewport\n" - "* Alt to disable for all viewports\n" - "* Ctrl to isolate visibility")); - UI_but_func_set(bt, hidebutton_base_flag_cb, view_layer, base); - UI_but_func_pushed_state_set(bt, base_pushed_state_cb, base); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - } - else { - bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, props.object_hide_viewport, -1, 0, 0, -1, -1, NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - } - - bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, props.object_hide_select, -1, 0, 0, -1, -1, NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - - bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, 0, 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, props.object_hide_render, -1, 0, 0, -1, -1, NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - - } - else if (tselem->type == TSE_MODIFIER) { - ModifierData *md = (ModifierData *)te->directdata; - - PointerRNA ptr; - RNA_pointer_create(tselem->id, &RNA_Modifier, md, &ptr); - - bt = uiDefIconButR_prop( - block, UI_BTYPE_ICON_TOGGLE, 0, 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, props.modifier_show_viewport, -1, 0, 0, -1, -1, NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - - bt = uiDefIconButR_prop( - block, UI_BTYPE_ICON_TOGGLE, 0, 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y, - &ptr, props.modifier_show_render, -1, 0, 0, -1, -1, NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - } - else if (tselem->type == TSE_POSE_CHANNEL) { - bPoseChannel *pchan = (bPoseChannel *)te->directdata; - Bone *bone = pchan->bone; - Object *ob = (Object *)tselem->id; - - bt = uiDefIconButBitI( - block, UI_BTYPE_ICON_TOGGLE, BONE_HIDDEN_P, 0, ICON_HIDE_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0, - TIP_("Restrict/Allow visibility in the 3D View")); - UI_but_func_set(bt, restrictbutton_bone_visibility_cb, ob->data, bone); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); - - bt = uiDefIconButBitI( - block, UI_BTYPE_ICON_TOGGLE, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &(bone->flag), 0, 0, 0, 0, - TIP_("Restrict/Allow selection in the 3D View")); - UI_but_func_set(bt, restrictbutton_bone_select_cb, ob->data, bone); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); - } - else if (tselem->type == TSE_EBONE) { - EditBone *ebone = (EditBone *)te->directdata; - - bt = uiDefIconButBitI( - block, UI_BTYPE_ICON_TOGGLE, BONE_HIDDEN_A, 0, ICON_RESTRICT_VIEW_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0, - TIP_("Restrict/Allow visibility in the 3D View")); - UI_but_func_set(bt, restrictbutton_ebone_visibility_cb, NULL, ebone); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); - - bt = uiDefIconButBitI( - block, UI_BTYPE_ICON_TOGGLE, BONE_UNSELECTABLE, 0, ICON_RESTRICT_SELECT_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &(ebone->flag), 0, 0, 0, 0, - TIP_("Restrict/Allow selection in the 3D View")); - UI_but_func_set(bt, restrictbutton_ebone_select_cb, NULL, ebone); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); - } - else if (tselem->type == TSE_GP_LAYER) { - ID *id = tselem->id; - bGPDlayer *gpl = (bGPDlayer *)te->directdata; - - bt = uiDefIconButBitS( - block, UI_BTYPE_ICON_TOGGLE, GP_LAYER_HIDE, 0, ICON_HIDE_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &gpl->flag, 0, 0, 0, 0, - TIP_("Restrict/Allow visibility in the 3D View")); - UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, id, gpl); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); - - bt = uiDefIconButBitS( - block, UI_BTYPE_ICON_TOGGLE, GP_LAYER_LOCKED, 0, ICON_UNLOCKED, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &gpl->flag, 0, 0, 0, 0, - TIP_("Restrict/Allow editing of strokes and keyframes in this layer")); - UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, id, gpl); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - } - else if (outliner_is_collection_tree_element(te)) { - LayerCollection *lc = (tselem->type == TSE_LAYER_COLLECTION) ? te->directdata : NULL; - Collection *collection = outliner_collection_from_tree_element(te); - - if ((!lc || !(lc->flag & LAYER_COLLECTION_EXCLUDE)) && - !(collection->flag & COLLECTION_IS_MASTER)) - { - PointerRNA collection_ptr; - RNA_id_pointer_create(&collection->id, &collection_ptr); - - if (lc != NULL) { - int icon = ICON_RESTRICT_VIEW_ON; - if ((collection->flag & COLLECTION_RESTRICT_VIEW) == 0) { - icon = (lc->flag & LAYER_COLLECTION_RESTRICT_VIEW) != 0 ? - ICON_HIDE_ON : - ICON_HIDE_OFF; - } - bt = uiDefIconBut( - block, UI_BTYPE_TOGGLE, 0, icon, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y, - NULL, 0, 0, 0, 0, - TIP_("Hide collection in viewport\n" - "* Alt to disable for all viewports\n" - "* Ctrl to isolate visibility\n" - "* Shift to hide inside objects and collections")); - UI_but_func_set(bt, hidebutton_layer_collection_flag_cb, view_layer, lc); - UI_but_func_pushed_state_set(bt, layer_collection_pushed_state_cb, lc); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - } - else { - bt = uiDefIconButR_prop( - block, UI_BTYPE_ICON_TOGGLE, 0, 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &collection_ptr, props.collection_hide_viewport, -1, 0, 0, 0, 0, NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - } - - bt = uiDefIconButR_prop( - block, UI_BTYPE_ICON_TOGGLE, 0, 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &collection_ptr, props.collection_hide_render, -1, 0, 0, 0, 0, NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - - bt = uiDefIconButR_prop( - block, UI_BTYPE_ICON_TOGGLE, 0, 0, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &collection_ptr, props.collection_hide_select, -1, 0, 0, 0, 0, NULL); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - } - } - } - - if (TSELEM_OPEN(tselem, soops)) { - outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &te->subtree); - } - } + /* Get RNA properties (once for speed). */ + static struct RestrictProperties { + bool initialized; + + PropertyRNA *object_hide_viewport, *object_hide_select, *object_hide_render; + PropertyRNA *collection_hide_viewport, *collection_hide_select, *collection_hide_render; + PropertyRNA *modifier_show_viewport, *modifier_show_render; + } props = {false}; + + if (!props.initialized) { + props.object_hide_viewport = RNA_struct_type_find_property(&RNA_Object, "hide_viewport"); + props.object_hide_select = RNA_struct_type_find_property(&RNA_Object, "hide_select"); + props.object_hide_render = RNA_struct_type_find_property(&RNA_Object, "hide_render"); + props.collection_hide_select = RNA_struct_type_find_property(&RNA_Collection, "hide_select"); + props.collection_hide_viewport = RNA_struct_type_find_property(&RNA_Collection, + "hide_viewport"); + props.collection_hide_render = RNA_struct_type_find_property(&RNA_Collection, "hide_render"); + props.modifier_show_viewport = RNA_struct_type_find_property(&RNA_Modifier, "show_viewport"); + props.modifier_show_render = RNA_struct_type_find_property(&RNA_Modifier, "show_render"); + + props.initialized = true; + } + + /* Create buttons. */ + uiBut *bt; + + for (TreeElement *te = lb->first; te; te = te->next) { + TreeStoreElem *tselem = TREESTORE(te); + if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) { + if (tselem->type == TSE_R_LAYER && (soops->outlinevis == SO_SCENES)) { + /* View layer render toggle. */ + ViewLayer *layer = te->directdata; + + bt = uiDefIconButBitS(block, + UI_BTYPE_ICON_TOGGLE_N, + VIEW_LAYER_RENDER, + 0, + ICON_RESTRICT_RENDER_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &layer->flag, + 0, + 0, + 0, + 0, + TIP_("Use view layer for rendering")); + UI_but_func_set(bt, restrictbutton_r_lay_cb, tselem->id, NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + } + else if (tselem->type == 0 && te->idcode == ID_OB) { + PointerRNA ptr; + Object *ob = (Object *)tselem->id; + RNA_pointer_create(&ob->id, &RNA_Object, ob, &ptr); + Base *base = BKE_view_layer_base_find(view_layer, ob); + + if (base) { + int icon = ICON_RESTRICT_VIEW_ON; + if ((ob->restrictflag & OB_RESTRICT_VIEW) == 0) { + icon = (base->flag & BASE_HIDDEN) != 0 ? ICON_HIDE_ON : ICON_HIDE_OFF; + } + bt = uiDefIconBut(block, + UI_BTYPE_ICON_TOGGLE, + 0, + icon, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + TIP_("Hide object in viewport\n" + "* Alt to disable for all viewports\n" + "* Ctrl to isolate visibility")); + UI_but_func_set(bt, hidebutton_base_flag_cb, view_layer, base); + UI_but_func_pushed_state_set(bt, base_pushed_state_cb, base); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } + else { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &ptr, + props.object_hide_viewport, + -1, + 0, + 0, + -1, + -1, + NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } + + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &ptr, + props.object_hide_select, + -1, + 0, + 0, + -1, + -1, + NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &ptr, + props.object_hide_render, + -1, + 0, + 0, + -1, + -1, + NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } + else if (tselem->type == TSE_MODIFIER) { + ModifierData *md = (ModifierData *)te->directdata; + + PointerRNA ptr; + RNA_pointer_create(tselem->id, &RNA_Modifier, md, &ptr); + + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &ptr, + props.modifier_show_viewport, + -1, + 0, + 0, + -1, + -1, + NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &ptr, + props.modifier_show_render, + -1, + 0, + 0, + -1, + -1, + NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } + else if (tselem->type == TSE_POSE_CHANNEL) { + bPoseChannel *pchan = (bPoseChannel *)te->directdata; + Bone *bone = pchan->bone; + Object *ob = (Object *)tselem->id; + + bt = uiDefIconButBitI(block, + UI_BTYPE_ICON_TOGGLE, + BONE_HIDDEN_P, + 0, + ICON_HIDE_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &(bone->flag), + 0, + 0, + 0, + 0, + TIP_("Restrict/Allow visibility in the 3D View")); + UI_but_func_set(bt, restrictbutton_bone_visibility_cb, ob->data, bone); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + + bt = uiDefIconButBitI(block, + UI_BTYPE_ICON_TOGGLE, + BONE_UNSELECTABLE, + 0, + ICON_RESTRICT_SELECT_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &(bone->flag), + 0, + 0, + 0, + 0, + TIP_("Restrict/Allow selection in the 3D View")); + UI_but_func_set(bt, restrictbutton_bone_select_cb, ob->data, bone); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + } + else if (tselem->type == TSE_EBONE) { + EditBone *ebone = (EditBone *)te->directdata; + + bt = uiDefIconButBitI(block, + UI_BTYPE_ICON_TOGGLE, + BONE_HIDDEN_A, + 0, + ICON_RESTRICT_VIEW_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &(ebone->flag), + 0, + 0, + 0, + 0, + TIP_("Restrict/Allow visibility in the 3D View")); + UI_but_func_set(bt, restrictbutton_ebone_visibility_cb, NULL, ebone); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + + bt = uiDefIconButBitI(block, + UI_BTYPE_ICON_TOGGLE, + BONE_UNSELECTABLE, + 0, + ICON_RESTRICT_SELECT_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &(ebone->flag), + 0, + 0, + 0, + 0, + TIP_("Restrict/Allow selection in the 3D View")); + UI_but_func_set(bt, restrictbutton_ebone_select_cb, NULL, ebone); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + } + else if (tselem->type == TSE_GP_LAYER) { + ID *id = tselem->id; + bGPDlayer *gpl = (bGPDlayer *)te->directdata; + + bt = uiDefIconButBitS(block, + UI_BTYPE_ICON_TOGGLE, + GP_LAYER_HIDE, + 0, + ICON_HIDE_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &gpl->flag, + 0, + 0, + 0, + 0, + TIP_("Restrict/Allow visibility in the 3D View")); + UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, id, gpl); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); + + bt = uiDefIconButBitS( + block, + UI_BTYPE_ICON_TOGGLE, + GP_LAYER_LOCKED, + 0, + ICON_UNLOCKED, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &gpl->flag, + 0, + 0, + 0, + 0, + TIP_("Restrict/Allow editing of strokes and keyframes in this layer")); + UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, id, gpl); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } + else if (outliner_is_collection_tree_element(te)) { + LayerCollection *lc = (tselem->type == TSE_LAYER_COLLECTION) ? te->directdata : NULL; + Collection *collection = outliner_collection_from_tree_element(te); + + if ((!lc || !(lc->flag & LAYER_COLLECTION_EXCLUDE)) && + !(collection->flag & COLLECTION_IS_MASTER)) { + PointerRNA collection_ptr; + RNA_id_pointer_create(&collection->id, &collection_ptr); + + if (lc != NULL) { + int icon = ICON_RESTRICT_VIEW_ON; + if ((collection->flag & COLLECTION_RESTRICT_VIEW) == 0) { + icon = (lc->flag & LAYER_COLLECTION_RESTRICT_VIEW) != 0 ? ICON_HIDE_ON : + ICON_HIDE_OFF; + } + bt = uiDefIconBut(block, + UI_BTYPE_TOGGLE, + 0, + icon, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0, + 0, + 0, + 0, + TIP_("Hide collection in viewport\n" + "* Alt to disable for all viewports\n" + "* Ctrl to isolate visibility\n" + "* Shift to hide inside objects and collections")); + UI_but_func_set(bt, hidebutton_layer_collection_flag_cb, view_layer, lc); + UI_but_func_pushed_state_set(bt, layer_collection_pushed_state_cb, lc); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } + else { + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &collection_ptr, + props.collection_hide_viewport, + -1, + 0, + 0, + 0, + 0, + NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } + + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &collection_ptr, + props.collection_hide_render, + -1, + 0, + 0, + 0, + 0, + NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + + bt = uiDefIconButR_prop(block, + UI_BTYPE_ICON_TOGGLE, + 0, + 0, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &collection_ptr, + props.collection_hide_select, + -1, + 0, + 0, + 0, + 0, + NULL); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } + } + } + + if (TSELEM_OPEN(tselem, soops)) { + outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &te->subtree); + } + } } static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOutliner *soops, ListBase *lb) { - for (TreeElement *te = lb->first; te; te = te->next) { - TreeStoreElem *tselem = TREESTORE(te); - if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) { - if (tselem->type == 0) { - uiBut *bt; - ID *id = tselem->id; - const char *tip = NULL; - int icon = ICON_NONE; - char buf[16] = ""; - int but_flag = UI_BUT_DRAG_LOCK; - - if (ID_IS_LINKED(id)) { - but_flag |= UI_BUT_DISABLED; - } - - if (id->flag & LIB_FAKEUSER) { - icon = ICON_FILE_TICK; - tip = TIP_("Data-block will be retained using a fake user"); - } - else { - icon = ICON_X; - tip = TIP_("Data-block has no users and will be deleted"); - } - bt = uiDefIconButBitS( - block, UI_BTYPE_TOGGLE, LIB_FAKEUSER, 1, icon, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y, - &id->flag, 0, 0, 0, 0, tip); - UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL); - UI_but_flag_enable(bt, but_flag); - - - BLI_str_format_int_grouped(buf, id->us); - bt = uiDefBut( - block, UI_BTYPE_BUT, 1, buf, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, - UI_UNIT_X, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, - TIP_("Number of users of this data-block")); - UI_but_flag_enable(bt, but_flag); - - - bt = uiDefButBitS( - block, UI_BTYPE_TOGGLE, LIB_FAKEUSER, 1, (id->flag & LIB_FAKEUSER) ? "F" : " ", - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), te->ys, UI_UNIT_X, UI_UNIT_Y, - &id->flag, 0, 0, 0, 0, - TIP_("Data-block has a 'fake' user which will keep it in the file " - "even if nothing else uses it")); - UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL); - UI_but_flag_enable(bt, but_flag); - } - } - - if (TSELEM_OPEN(tselem, soops)) { - outliner_draw_userbuts(block, ar, soops, &te->subtree); - } - } + for (TreeElement *te = lb->first; te; te = te->next) { + TreeStoreElem *tselem = TREESTORE(te); + if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) { + if (tselem->type == 0) { + uiBut *bt; + ID *id = tselem->id; + const char *tip = NULL; + int icon = ICON_NONE; + char buf[16] = ""; + int but_flag = UI_BUT_DRAG_LOCK; + + if (ID_IS_LINKED(id)) { + but_flag |= UI_BUT_DISABLED; + } + + if (id->flag & LIB_FAKEUSER) { + icon = ICON_FILE_TICK; + tip = TIP_("Data-block will be retained using a fake user"); + } + else { + icon = ICON_X; + tip = TIP_("Data-block has no users and will be deleted"); + } + bt = uiDefIconButBitS(block, + UI_BTYPE_TOGGLE, + LIB_FAKEUSER, + 1, + icon, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &id->flag, + 0, + 0, + 0, + 0, + tip); + UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL); + UI_but_flag_enable(bt, but_flag); + + BLI_str_format_int_grouped(buf, id->us); + bt = uiDefBut(block, + UI_BTYPE_BUT, + 1, + buf, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0, + 0, + TIP_("Number of users of this data-block")); + UI_but_flag_enable(bt, but_flag); + + bt = uiDefButBitS(block, + UI_BTYPE_TOGGLE, + LIB_FAKEUSER, + 1, + (id->flag & LIB_FAKEUSER) ? "F" : " ", + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + &id->flag, + 0, + 0, + 0, + 0, + TIP_("Data-block has a 'fake' user which will keep it in the file " + "even if nothing else uses it")); + UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL); + UI_but_flag_enable(bt, but_flag); + } + } + + if (TSELEM_OPEN(tselem, soops)) { + outliner_draw_userbuts(block, ar, soops, &te->subtree); + } + } } static void outliner_draw_rnacols(ARegion *ar, int sizex) { - View2D *v2d = &ar->v2d; + View2D *v2d = &ar->v2d; - float miny = v2d->cur.ymin; - if (miny < v2d->tot.ymin) { - miny = v2d->tot.ymin; - } + float miny = v2d->cur.ymin; + if (miny < v2d->tot.ymin) { + miny = v2d->tot.ymin; + } - GPU_line_width(1.0f); + GPU_line_width(1.0f); - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformThemeColorShadeAlpha(TH_BACK, -15, -200); + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColorShadeAlpha(TH_BACK, -15, -200); - immBegin(GPU_PRIM_LINES, 4); + immBegin(GPU_PRIM_LINES, 4); - immVertex2f(pos, sizex, v2d->cur.ymax); - immVertex2f(pos, sizex, miny); + immVertex2f(pos, sizex, v2d->cur.ymax); + immVertex2f(pos, sizex, miny); - immVertex2f(pos, sizex + OL_RNA_COL_SIZEX, v2d->cur.ymax); - immVertex2f(pos, sizex + OL_RNA_COL_SIZEX, miny); + immVertex2f(pos, sizex + OL_RNA_COL_SIZEX, v2d->cur.ymax); + immVertex2f(pos, sizex + OL_RNA_COL_SIZEX, miny); - immEnd(); + immEnd(); - immUnbindProgram(); + immUnbindProgram(); } -static void outliner_draw_rnabuts(uiBlock *block, ARegion *ar, SpaceOutliner *soops, int sizex, ListBase *lb) +static void outliner_draw_rnabuts( + uiBlock *block, ARegion *ar, SpaceOutliner *soops, int sizex, ListBase *lb) { - PointerRNA *ptr; - PropertyRNA *prop; - - for (TreeElement *te = lb->first; te; te = te->next) { - TreeStoreElem *tselem = TREESTORE(te); - if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) { - if (tselem->type == TSE_RNA_PROPERTY) { - ptr = &te->rnaptr; - prop = te->directdata; - - if (!TSELEM_OPEN(tselem, soops)) { - if (RNA_property_type(prop) == PROP_POINTER) { - uiBut *but = uiDefAutoButR( - block, ptr, prop, -1, "", ICON_NONE, sizex, te->ys, - OL_RNA_COL_SIZEX, UI_UNIT_Y - 1); - UI_but_flag_enable(but, UI_BUT_DISABLED); - } - else if (RNA_property_type(prop) == PROP_ENUM) { - uiDefAutoButR( - block, ptr, prop, -1, NULL, ICON_NONE, sizex, te->ys, OL_RNA_COL_SIZEX, - UI_UNIT_Y - 1); - } - else { - uiDefAutoButR( - block, ptr, prop, -1, "", ICON_NONE, sizex, te->ys, OL_RNA_COL_SIZEX, - UI_UNIT_Y - 1); - } - } - } - else if (tselem->type == TSE_RNA_ARRAY_ELEM) { - ptr = &te->rnaptr; - prop = te->directdata; - - uiDefAutoButR( - block, ptr, prop, te->index, "", ICON_NONE, sizex, te->ys, OL_RNA_COL_SIZEX, - UI_UNIT_Y - 1); - } - } - - if (TSELEM_OPEN(tselem, soops)) { - outliner_draw_rnabuts(block, ar, soops, sizex, &te->subtree); - } - } + PointerRNA *ptr; + PropertyRNA *prop; + + for (TreeElement *te = lb->first; te; te = te->next) { + TreeStoreElem *tselem = TREESTORE(te); + if (te->ys + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && te->ys <= ar->v2d.cur.ymax) { + if (tselem->type == TSE_RNA_PROPERTY) { + ptr = &te->rnaptr; + prop = te->directdata; + + if (!TSELEM_OPEN(tselem, soops)) { + if (RNA_property_type(prop) == PROP_POINTER) { + uiBut *but = uiDefAutoButR(block, + ptr, + prop, + -1, + "", + ICON_NONE, + sizex, + te->ys, + OL_RNA_COL_SIZEX, + UI_UNIT_Y - 1); + UI_but_flag_enable(but, UI_BUT_DISABLED); + } + else if (RNA_property_type(prop) == PROP_ENUM) { + uiDefAutoButR(block, + ptr, + prop, + -1, + NULL, + ICON_NONE, + sizex, + te->ys, + OL_RNA_COL_SIZEX, + UI_UNIT_Y - 1); + } + else { + uiDefAutoButR(block, + ptr, + prop, + -1, + "", + ICON_NONE, + sizex, + te->ys, + OL_RNA_COL_SIZEX, + UI_UNIT_Y - 1); + } + } + } + else if (tselem->type == TSE_RNA_ARRAY_ELEM) { + ptr = &te->rnaptr; + prop = te->directdata; + + uiDefAutoButR(block, + ptr, + prop, + te->index, + "", + ICON_NONE, + sizex, + te->ys, + OL_RNA_COL_SIZEX, + UI_UNIT_Y - 1); + } + } + + if (TSELEM_OPEN(tselem, soops)) { + outliner_draw_rnabuts(block, ar, soops, sizex, &te->subtree); + } + } } static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, TreeElement *te) { - uiBut *bt; - TreeStoreElem *tselem; - int spx, dx, len; - - tselem = TREESTORE(te); - - BLI_assert(tselem->flag & TSE_TEXTBUT); - /* If we add support to rename Sequence. - * need change this. - */ - - if (tselem->type == TSE_EBONE) { - len = sizeof(((EditBone *) 0)->name); - } - else if (tselem->type == TSE_MODIFIER) { - len = sizeof(((ModifierData *) 0)->name); - } - else if (tselem->id && GS(tselem->id->name) == ID_LI) { - len = sizeof(((Library *) 0)->name); - } - else { - len = MAX_ID_NAME - 2; - } - - spx = te->xs + 1.8f * UI_UNIT_X; - dx = ar->v2d.cur.xmax - (spx + 3.2f * UI_UNIT_X); - - bt = uiDefBut( - block, UI_BTYPE_TEXT, OL_NAMEBUTTON, "", spx, te->ys, dx, UI_UNIT_Y - 1, (void *)te->name, - 1.0, (float)len, 0, 0, ""); - UI_but_func_rename_set(bt, namebutton_cb, tselem); - - /* returns false if button got removed */ - if (false == UI_but_active_only(C, ar, block, bt)) { - tselem->flag &= ~TSE_TEXTBUT; - - /* bad! (notifier within draw) without this, we don't get a refresh */ - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); - } + uiBut *bt; + TreeStoreElem *tselem; + int spx, dx, len; + + tselem = TREESTORE(te); + + BLI_assert(tselem->flag & TSE_TEXTBUT); + /* If we add support to rename Sequence. + * need change this. + */ + + if (tselem->type == TSE_EBONE) { + len = sizeof(((EditBone *)0)->name); + } + else if (tselem->type == TSE_MODIFIER) { + len = sizeof(((ModifierData *)0)->name); + } + else if (tselem->id && GS(tselem->id->name) == ID_LI) { + len = sizeof(((Library *)0)->name); + } + else { + len = MAX_ID_NAME - 2; + } + + spx = te->xs + 1.8f * UI_UNIT_X; + dx = ar->v2d.cur.xmax - (spx + 3.2f * UI_UNIT_X); + + bt = uiDefBut(block, + UI_BTYPE_TEXT, + OL_NAMEBUTTON, + "", + spx, + te->ys, + dx, + UI_UNIT_Y - 1, + (void *)te->name, + 1.0, + (float)len, + 0, + 0, + ""); + UI_but_func_rename_set(bt, namebutton_cb, tselem); + + /* returns false if button got removed */ + if (false == UI_but_active_only(C, ar, block, bt)) { + tselem->flag &= ~TSE_TEXTBUT; + + /* bad! (notifier within draw) without this, we don't get a refresh */ + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); + } } /* ****************************************************** */ @@ -972,615 +1234,674 @@ static void outliner_buttons(const bContext *C, uiBlock *block, ARegion *ar, Tre TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) { - TreeElementIcon data = {0}; - - if (tselem->type) { - switch (tselem->type) { - case TSE_ANIM_DATA: - data.icon = ICON_ANIM_DATA; /* XXX */ - break; - case TSE_NLA: - data.icon = ICON_NLA; - break; - case TSE_NLA_TRACK: - data.icon = ICON_NLA; /* XXX */ - break; - case TSE_NLA_ACTION: - data.icon = ICON_ACTION; - break; - case TSE_DRIVER_BASE: - data.icon = ICON_DRIVER; - break; - case TSE_DEFGROUP_BASE: - data.icon = ICON_GROUP_VERTEX; - break; - case TSE_BONE: - case TSE_EBONE: - data.icon = ICON_BONE_DATA; - break; - case TSE_CONSTRAINT_BASE: - data.icon = ICON_CONSTRAINT; - break; - case TSE_MODIFIER_BASE: - data.icon = ICON_MODIFIER_DATA; - break; - case TSE_LINKED_OB: - data.icon = ICON_OBJECT_DATA; - break; - case TSE_LINKED_PSYS: - data.icon = ICON_PARTICLES; - break; - case TSE_MODIFIER: - { - Object *ob = (Object *)tselem->id; - if (ob->type != OB_GPENCIL) { - ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr); - switch ((ModifierType)md->type) { - case eModifierType_Subsurf: - data.icon = ICON_MOD_SUBSURF; - break; - case eModifierType_Armature: - data.icon = ICON_MOD_ARMATURE; - break; - case eModifierType_Lattice: - data.icon = ICON_MOD_LATTICE; - break; - case eModifierType_Curve: - data.icon = ICON_MOD_CURVE; - break; - case eModifierType_Build: - data.icon = ICON_MOD_BUILD; - break; - case eModifierType_Mirror: - data.icon = ICON_MOD_MIRROR; - break; - case eModifierType_Decimate: - data.icon = ICON_MOD_DECIM; - break; - case eModifierType_Wave: - data.icon = ICON_MOD_WAVE; - break; - case eModifierType_Hook: - data.icon = ICON_HOOK; - break; - case eModifierType_Softbody: - data.icon = ICON_MOD_SOFT; - break; - case eModifierType_Boolean: - data.icon = ICON_MOD_BOOLEAN; - break; - case eModifierType_ParticleSystem: - data.icon = ICON_MOD_PARTICLES; - break; - case eModifierType_ParticleInstance: - data.icon = ICON_MOD_PARTICLES; - break; - case eModifierType_EdgeSplit: - data.icon = ICON_MOD_EDGESPLIT; - break; - case eModifierType_Array: - data.icon = ICON_MOD_ARRAY; - break; - case eModifierType_UVProject: - case eModifierType_UVWarp: /* TODO, get own icon */ - data.icon = ICON_MOD_UVPROJECT; - break; - case eModifierType_Displace: - data.icon = ICON_MOD_DISPLACE; - break; - case eModifierType_Shrinkwrap: - data.icon = ICON_MOD_SHRINKWRAP; - break; - case eModifierType_Cast: - data.icon = ICON_MOD_CAST; - break; - case eModifierType_MeshDeform: - case eModifierType_SurfaceDeform: - data.icon = ICON_MOD_MESHDEFORM; - break; - case eModifierType_Bevel: - data.icon = ICON_MOD_BEVEL; - break; - case eModifierType_Smooth: - case eModifierType_LaplacianSmooth: - case eModifierType_CorrectiveSmooth: - data.icon = ICON_MOD_SMOOTH; - break; - case eModifierType_SimpleDeform: - data.icon = ICON_MOD_SIMPLEDEFORM; - break; - case eModifierType_Mask: - data.icon = ICON_MOD_MASK; - break; - case eModifierType_Cloth: - data.icon = ICON_MOD_CLOTH; - break; - case eModifierType_Explode: - data.icon = ICON_MOD_EXPLODE; - break; - case eModifierType_Collision: - case eModifierType_Surface: - data.icon = ICON_MOD_PHYSICS; - break; - case eModifierType_Fluidsim: - data.icon = ICON_MOD_FLUIDSIM; - break; - case eModifierType_Multires: - data.icon = ICON_MOD_MULTIRES; - break; - case eModifierType_Smoke: - data.icon = ICON_MOD_SMOKE; - break; - case eModifierType_Solidify: - data.icon = ICON_MOD_SOLIDIFY; - break; - case eModifierType_Screw: - data.icon = ICON_MOD_SCREW; - break; - case eModifierType_Remesh: - data.icon = ICON_MOD_REMESH; - break; - case eModifierType_WeightVGEdit: - case eModifierType_WeightVGMix: - case eModifierType_WeightVGProximity: - data.icon = ICON_MOD_VERTEX_WEIGHT; - break; - case eModifierType_DynamicPaint: - data.icon = ICON_MOD_DYNAMICPAINT; - break; - case eModifierType_Ocean: - data.icon = ICON_MOD_OCEAN; - break; - case eModifierType_Warp: - data.icon = ICON_MOD_WARP; - break; - case eModifierType_Skin: - data.icon = ICON_MOD_SKIN; - break; - case eModifierType_Triangulate: - data.icon = ICON_MOD_TRIANGULATE; - break; - case eModifierType_MeshCache: - data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */ - break; - case eModifierType_MeshSequenceCache: - data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */ - break; - case eModifierType_Wireframe: - data.icon = ICON_MOD_WIREFRAME; - break; - case eModifierType_LaplacianDeform: - data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */ - break; - case eModifierType_DataTransfer: - data.icon = ICON_MOD_DATA_TRANSFER; - break; - case eModifierType_NormalEdit: - case eModifierType_WeightedNormal: - data.icon = ICON_MOD_NORMALEDIT; - break; - /* Default */ - case eModifierType_None: - case eModifierType_ShapeKey: - - case NUM_MODIFIER_TYPES: - data.icon = ICON_DOT; - break; - } - } - else { - /* grease pencil modifiers */ - GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, tselem->nr); - switch ((GpencilModifierType)md->type) { - case eGpencilModifierType_Noise: - data.icon = ICON_RNDCURVE; - break; - case eGpencilModifierType_Subdiv: - data.icon = ICON_MOD_SUBSURF; - break; - case eGpencilModifierType_Thick: - data.icon = ICON_MOD_THICKNESS; - break; - case eGpencilModifierType_Tint: - data.icon = ICON_MOD_TINT; - break; - case eGpencilModifierType_Array: - data.icon = ICON_MOD_ARRAY; - break; - case eGpencilModifierType_Build: - data.icon = ICON_MOD_BUILD; - break; - case eGpencilModifierType_Opacity: - data.icon = ICON_MOD_MASK; - break; - case eGpencilModifierType_Color: - data.icon = ICON_MOD_HUE_SATURATION; - break; - case eGpencilModifierType_Lattice: - data.icon = ICON_MOD_LATTICE; - break; - case eGpencilModifierType_Mirror: - data.icon = ICON_MOD_MIRROR; - break; - case eGpencilModifierType_Simplify: - data.icon = ICON_MOD_SIMPLIFY; - break; - case eGpencilModifierType_Smooth: - data.icon = ICON_MOD_SMOOTH; - break; - case eGpencilModifierType_Hook: - data.icon = ICON_HOOK; - break; - case eGpencilModifierType_Offset: - data.icon = ICON_MOD_OFFSET; - break; - case eGpencilModifierType_Armature: - data.icon = ICON_MOD_ARMATURE; - break; - - /* Default */ - default: - data.icon = ICON_DOT; - break; - } - } - break; - } - case TSE_POSE_BASE: - data.icon = ICON_ARMATURE_DATA; - break; - case TSE_POSE_CHANNEL: - data.icon = ICON_BONE_DATA; - break; - case TSE_PROXY: - data.icon = ICON_GHOST_ENABLED; - break; - case TSE_R_LAYER_BASE: - data.icon = ICON_RENDERLAYERS; - break; - case TSE_SCENE_OBJECTS_BASE: - data.icon = ICON_OUTLINER_OB_GROUP_INSTANCE; - break; - case TSE_R_LAYER: - data.icon = ICON_RENDER_RESULT; - break; - case TSE_LINKED_LAMP: - data.icon = ICON_LIGHT_DATA; - break; - case TSE_LINKED_MAT: - data.icon = ICON_MATERIAL_DATA; - break; - case TSE_POSEGRP_BASE: - data.icon = ICON_GROUP_BONE; - break; - case TSE_SEQUENCE: - if (te->idcode == SEQ_TYPE_MOVIE) { - data.icon = ICON_SEQUENCE; - } - else if (te->idcode == SEQ_TYPE_META) { - data.icon = ICON_DOT; - } - else if (te->idcode == SEQ_TYPE_SCENE) { - data.icon = ICON_SCENE; - } - else if (te->idcode == SEQ_TYPE_SOUND_RAM) { - data.icon = ICON_SOUND; - } - else if (te->idcode == SEQ_TYPE_IMAGE) { - data.icon = ICON_IMAGE; - } - else { - data.icon = ICON_PARTICLES; - } - break; - case TSE_SEQ_STRIP: - data.icon = ICON_LIBRARY_DATA_DIRECT; - break; - case TSE_SEQUENCE_DUP: - data.icon = ICON_OBJECT_DATA; - break; - case TSE_RNA_STRUCT: - if (RNA_struct_is_ID(te->rnaptr.type)) { - data.drag_id = (ID *)te->rnaptr.data; - data.icon = RNA_struct_ui_icon(te->rnaptr.type); - } - else { - data.icon = RNA_struct_ui_icon(te->rnaptr.type); - } - break; - case TSE_LAYER_COLLECTION: - case TSE_SCENE_COLLECTION_BASE: - case TSE_VIEW_COLLECTION_BASE: - { - Collection *collection = outliner_collection_from_tree_element(te); - if (collection && !(collection->flag & COLLECTION_IS_MASTER)) { - data.drag_id = tselem->id; - data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL; - } - - data.icon = ICON_GROUP; - break; - } - /* Removed the icons from outliner. Need a better structure with Layers, Palettes and Colors */ - case TSE_GP_LAYER: - { - /* indicate whether layer is active */ - bGPDlayer *gpl = te->directdata; - if (gpl->flag & GP_LAYER_ACTIVE) { - data.icon = ICON_GREASEPENCIL; - } - else { - data.icon = ICON_DOT; - } - break; - } - default: - data.icon = ICON_DOT; - break; - } - } - else if (tselem->id) { - data.drag_id = tselem->id; - data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL; - - if (GS(tselem->id->name) == ID_OB) { - Object *ob = (Object *)tselem->id; - switch (ob->type) { - case OB_LAMP: - data.icon = ICON_OUTLINER_OB_LIGHT; break; - case OB_MESH: - data.icon = ICON_OUTLINER_OB_MESH; break; - case OB_CAMERA: - data.icon = ICON_OUTLINER_OB_CAMERA; break; - case OB_CURVE: - data.icon = ICON_OUTLINER_OB_CURVE; break; - case OB_MBALL: - data.icon = ICON_OUTLINER_OB_META; break; - case OB_LATTICE: - data.icon = ICON_OUTLINER_OB_LATTICE; break; - case OB_ARMATURE: - data.icon = ICON_OUTLINER_OB_ARMATURE; break; - case OB_FONT: - data.icon = ICON_OUTLINER_OB_FONT; break; - case OB_SURF: - data.icon = ICON_OUTLINER_OB_SURFACE; break; - case OB_SPEAKER: - data.icon = ICON_OUTLINER_OB_SPEAKER; break; - case OB_LIGHTPROBE: - data.icon = ICON_OUTLINER_OB_LIGHTPROBE; break; - case OB_EMPTY: - if (ob->instance_collection) { - data.icon = ICON_OUTLINER_OB_GROUP_INSTANCE; - } - else if (ob->empty_drawtype == OB_EMPTY_IMAGE) { - data.icon = ICON_OUTLINER_OB_IMAGE; - } - else { - data.icon = ICON_OUTLINER_OB_EMPTY; - } - break; - case OB_GPENCIL: - data.icon = ICON_OUTLINER_OB_GREASEPENCIL; break; - break; - } - } - else { - /* TODO(sergey): Casting to short here just to handle ID_NLA which is - * NOT inside of IDType enum. - */ - switch ((short)GS(tselem->id->name)) { - case ID_SCE: - data.icon = ICON_SCENE_DATA; break; - case ID_ME: - data.icon = ICON_OUTLINER_DATA_MESH; break; - case ID_CU: - data.icon = ICON_OUTLINER_DATA_CURVE; break; - case ID_MB: - data.icon = ICON_OUTLINER_DATA_META; break; - case ID_LT: - data.icon = ICON_OUTLINER_DATA_LATTICE; break; - case ID_LA: - { - Light *la = (Light *)tselem->id; - switch (la->type) { - case LA_LOCAL: - data.icon = ICON_LIGHT_POINT; break; - case LA_SUN: - data.icon = ICON_LIGHT_SUN; break; - case LA_SPOT: - data.icon = ICON_LIGHT_SPOT; break; - case LA_AREA: - data.icon = ICON_LIGHT_AREA; break; - default: - data.icon = ICON_OUTLINER_DATA_LIGHT; break; - } - break; - } - case ID_MA: - data.icon = ICON_MATERIAL_DATA; break; - case ID_TE: - data.icon = ICON_TEXTURE_DATA; break; - case ID_IM: - data.icon = ICON_IMAGE_DATA; break; - case ID_SPK: - case ID_SO: - data.icon = ICON_OUTLINER_DATA_SPEAKER; break; - case ID_AR: - data.icon = ICON_OUTLINER_DATA_ARMATURE; break; - case ID_CA: - data.icon = ICON_OUTLINER_DATA_CAMERA; break; - case ID_KE: - data.icon = ICON_SHAPEKEY_DATA; break; - case ID_WO: - data.icon = ICON_WORLD_DATA; break; - case ID_AC: - data.icon = ICON_ACTION; break; - case ID_NLA: - data.icon = ICON_NLA; break; - case ID_TXT: - data.icon = ICON_SCRIPT; break; - case ID_GR: - data.icon = ICON_GROUP; break; - case ID_LI: - if (tselem->id->tag & LIB_TAG_MISSING) { - data.icon = ICON_LIBRARY_DATA_BROKEN; - } - else if (((Library *)tselem->id)->parent) { - data.icon = ICON_LIBRARY_DATA_INDIRECT; - } - else { - data.icon = ICON_LIBRARY_DATA_DIRECT; - } - break; - case ID_LS: - data.icon = ICON_LINE_DATA; break; - case ID_GD: - data.icon = ICON_OUTLINER_DATA_GREASEPENCIL; break; - case ID_LP: - { - LightProbe *lp = (LightProbe *)tselem->id; - switch (lp->type) { - case LIGHTPROBE_TYPE_CUBE: - data.icon = ICON_LIGHTPROBE_CUBEMAP; break; - case LIGHTPROBE_TYPE_PLANAR: - data.icon = ICON_LIGHTPROBE_PLANAR; break; - case LIGHTPROBE_TYPE_GRID: - data.icon = ICON_LIGHTPROBE_GRID; break; - default: - data.icon = ICON_LIGHTPROBE_CUBEMAP; break; - } - break; - } - case ID_BR: - data.icon = ICON_BRUSH_DATA; break; - case ID_SCR: - case ID_WS: - data.icon = ICON_WORKSPACE; break; - case ID_MSK: - data.icon = ICON_MOD_MASK; break; - case ID_MC: - data.icon = ICON_SEQUENCE; break; - case ID_PC: - data.icon = ICON_CURVE_BEZCURVE; break; - default: - break; - } - } - } - - return data; + TreeElementIcon data = {0}; + + if (tselem->type) { + switch (tselem->type) { + case TSE_ANIM_DATA: + data.icon = ICON_ANIM_DATA; /* XXX */ + break; + case TSE_NLA: + data.icon = ICON_NLA; + break; + case TSE_NLA_TRACK: + data.icon = ICON_NLA; /* XXX */ + break; + case TSE_NLA_ACTION: + data.icon = ICON_ACTION; + break; + case TSE_DRIVER_BASE: + data.icon = ICON_DRIVER; + break; + case TSE_DEFGROUP_BASE: + data.icon = ICON_GROUP_VERTEX; + break; + case TSE_BONE: + case TSE_EBONE: + data.icon = ICON_BONE_DATA; + break; + case TSE_CONSTRAINT_BASE: + data.icon = ICON_CONSTRAINT; + break; + case TSE_MODIFIER_BASE: + data.icon = ICON_MODIFIER_DATA; + break; + case TSE_LINKED_OB: + data.icon = ICON_OBJECT_DATA; + break; + case TSE_LINKED_PSYS: + data.icon = ICON_PARTICLES; + break; + case TSE_MODIFIER: { + Object *ob = (Object *)tselem->id; + if (ob->type != OB_GPENCIL) { + ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr); + switch ((ModifierType)md->type) { + case eModifierType_Subsurf: + data.icon = ICON_MOD_SUBSURF; + break; + case eModifierType_Armature: + data.icon = ICON_MOD_ARMATURE; + break; + case eModifierType_Lattice: + data.icon = ICON_MOD_LATTICE; + break; + case eModifierType_Curve: + data.icon = ICON_MOD_CURVE; + break; + case eModifierType_Build: + data.icon = ICON_MOD_BUILD; + break; + case eModifierType_Mirror: + data.icon = ICON_MOD_MIRROR; + break; + case eModifierType_Decimate: + data.icon = ICON_MOD_DECIM; + break; + case eModifierType_Wave: + data.icon = ICON_MOD_WAVE; + break; + case eModifierType_Hook: + data.icon = ICON_HOOK; + break; + case eModifierType_Softbody: + data.icon = ICON_MOD_SOFT; + break; + case eModifierType_Boolean: + data.icon = ICON_MOD_BOOLEAN; + break; + case eModifierType_ParticleSystem: + data.icon = ICON_MOD_PARTICLES; + break; + case eModifierType_ParticleInstance: + data.icon = ICON_MOD_PARTICLES; + break; + case eModifierType_EdgeSplit: + data.icon = ICON_MOD_EDGESPLIT; + break; + case eModifierType_Array: + data.icon = ICON_MOD_ARRAY; + break; + case eModifierType_UVProject: + case eModifierType_UVWarp: /* TODO, get own icon */ + data.icon = ICON_MOD_UVPROJECT; + break; + case eModifierType_Displace: + data.icon = ICON_MOD_DISPLACE; + break; + case eModifierType_Shrinkwrap: + data.icon = ICON_MOD_SHRINKWRAP; + break; + case eModifierType_Cast: + data.icon = ICON_MOD_CAST; + break; + case eModifierType_MeshDeform: + case eModifierType_SurfaceDeform: + data.icon = ICON_MOD_MESHDEFORM; + break; + case eModifierType_Bevel: + data.icon = ICON_MOD_BEVEL; + break; + case eModifierType_Smooth: + case eModifierType_LaplacianSmooth: + case eModifierType_CorrectiveSmooth: + data.icon = ICON_MOD_SMOOTH; + break; + case eModifierType_SimpleDeform: + data.icon = ICON_MOD_SIMPLEDEFORM; + break; + case eModifierType_Mask: + data.icon = ICON_MOD_MASK; + break; + case eModifierType_Cloth: + data.icon = ICON_MOD_CLOTH; + break; + case eModifierType_Explode: + data.icon = ICON_MOD_EXPLODE; + break; + case eModifierType_Collision: + case eModifierType_Surface: + data.icon = ICON_MOD_PHYSICS; + break; + case eModifierType_Fluidsim: + data.icon = ICON_MOD_FLUIDSIM; + break; + case eModifierType_Multires: + data.icon = ICON_MOD_MULTIRES; + break; + case eModifierType_Smoke: + data.icon = ICON_MOD_SMOKE; + break; + case eModifierType_Solidify: + data.icon = ICON_MOD_SOLIDIFY; + break; + case eModifierType_Screw: + data.icon = ICON_MOD_SCREW; + break; + case eModifierType_Remesh: + data.icon = ICON_MOD_REMESH; + break; + case eModifierType_WeightVGEdit: + case eModifierType_WeightVGMix: + case eModifierType_WeightVGProximity: + data.icon = ICON_MOD_VERTEX_WEIGHT; + break; + case eModifierType_DynamicPaint: + data.icon = ICON_MOD_DYNAMICPAINT; + break; + case eModifierType_Ocean: + data.icon = ICON_MOD_OCEAN; + break; + case eModifierType_Warp: + data.icon = ICON_MOD_WARP; + break; + case eModifierType_Skin: + data.icon = ICON_MOD_SKIN; + break; + case eModifierType_Triangulate: + data.icon = ICON_MOD_TRIANGULATE; + break; + case eModifierType_MeshCache: + data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */ + break; + case eModifierType_MeshSequenceCache: + data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */ + break; + case eModifierType_Wireframe: + data.icon = ICON_MOD_WIREFRAME; + break; + case eModifierType_LaplacianDeform: + data.icon = ICON_MOD_MESHDEFORM; /* XXX, needs own icon */ + break; + case eModifierType_DataTransfer: + data.icon = ICON_MOD_DATA_TRANSFER; + break; + case eModifierType_NormalEdit: + case eModifierType_WeightedNormal: + data.icon = ICON_MOD_NORMALEDIT; + break; + /* Default */ + case eModifierType_None: + case eModifierType_ShapeKey: + + case NUM_MODIFIER_TYPES: + data.icon = ICON_DOT; + break; + } + } + else { + /* grease pencil modifiers */ + GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, tselem->nr); + switch ((GpencilModifierType)md->type) { + case eGpencilModifierType_Noise: + data.icon = ICON_RNDCURVE; + break; + case eGpencilModifierType_Subdiv: + data.icon = ICON_MOD_SUBSURF; + break; + case eGpencilModifierType_Thick: + data.icon = ICON_MOD_THICKNESS; + break; + case eGpencilModifierType_Tint: + data.icon = ICON_MOD_TINT; + break; + case eGpencilModifierType_Array: + data.icon = ICON_MOD_ARRAY; + break; + case eGpencilModifierType_Build: + data.icon = ICON_MOD_BUILD; + break; + case eGpencilModifierType_Opacity: + data.icon = ICON_MOD_MASK; + break; + case eGpencilModifierType_Color: + data.icon = ICON_MOD_HUE_SATURATION; + break; + case eGpencilModifierType_Lattice: + data.icon = ICON_MOD_LATTICE; + break; + case eGpencilModifierType_Mirror: + data.icon = ICON_MOD_MIRROR; + break; + case eGpencilModifierType_Simplify: + data.icon = ICON_MOD_SIMPLIFY; + break; + case eGpencilModifierType_Smooth: + data.icon = ICON_MOD_SMOOTH; + break; + case eGpencilModifierType_Hook: + data.icon = ICON_HOOK; + break; + case eGpencilModifierType_Offset: + data.icon = ICON_MOD_OFFSET; + break; + case eGpencilModifierType_Armature: + data.icon = ICON_MOD_ARMATURE; + break; + + /* Default */ + default: + data.icon = ICON_DOT; + break; + } + } + break; + } + case TSE_POSE_BASE: + data.icon = ICON_ARMATURE_DATA; + break; + case TSE_POSE_CHANNEL: + data.icon = ICON_BONE_DATA; + break; + case TSE_PROXY: + data.icon = ICON_GHOST_ENABLED; + break; + case TSE_R_LAYER_BASE: + data.icon = ICON_RENDERLAYERS; + break; + case TSE_SCENE_OBJECTS_BASE: + data.icon = ICON_OUTLINER_OB_GROUP_INSTANCE; + break; + case TSE_R_LAYER: + data.icon = ICON_RENDER_RESULT; + break; + case TSE_LINKED_LAMP: + data.icon = ICON_LIGHT_DATA; + break; + case TSE_LINKED_MAT: + data.icon = ICON_MATERIAL_DATA; + break; + case TSE_POSEGRP_BASE: + data.icon = ICON_GROUP_BONE; + break; + case TSE_SEQUENCE: + if (te->idcode == SEQ_TYPE_MOVIE) { + data.icon = ICON_SEQUENCE; + } + else if (te->idcode == SEQ_TYPE_META) { + data.icon = ICON_DOT; + } + else if (te->idcode == SEQ_TYPE_SCENE) { + data.icon = ICON_SCENE; + } + else if (te->idcode == SEQ_TYPE_SOUND_RAM) { + data.icon = ICON_SOUND; + } + else if (te->idcode == SEQ_TYPE_IMAGE) { + data.icon = ICON_IMAGE; + } + else { + data.icon = ICON_PARTICLES; + } + break; + case TSE_SEQ_STRIP: + data.icon = ICON_LIBRARY_DATA_DIRECT; + break; + case TSE_SEQUENCE_DUP: + data.icon = ICON_OBJECT_DATA; + break; + case TSE_RNA_STRUCT: + if (RNA_struct_is_ID(te->rnaptr.type)) { + data.drag_id = (ID *)te->rnaptr.data; + data.icon = RNA_struct_ui_icon(te->rnaptr.type); + } + else { + data.icon = RNA_struct_ui_icon(te->rnaptr.type); + } + break; + case TSE_LAYER_COLLECTION: + case TSE_SCENE_COLLECTION_BASE: + case TSE_VIEW_COLLECTION_BASE: { + Collection *collection = outliner_collection_from_tree_element(te); + if (collection && !(collection->flag & COLLECTION_IS_MASTER)) { + data.drag_id = tselem->id; + data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL; + } + + data.icon = ICON_GROUP; + break; + } + /* Removed the icons from outliner. Need a better structure with Layers, Palettes and Colors */ + case TSE_GP_LAYER: { + /* indicate whether layer is active */ + bGPDlayer *gpl = te->directdata; + if (gpl->flag & GP_LAYER_ACTIVE) { + data.icon = ICON_GREASEPENCIL; + } + else { + data.icon = ICON_DOT; + } + break; + } + default: + data.icon = ICON_DOT; + break; + } + } + else if (tselem->id) { + data.drag_id = tselem->id; + data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL; + + if (GS(tselem->id->name) == ID_OB) { + Object *ob = (Object *)tselem->id; + switch (ob->type) { + case OB_LAMP: + data.icon = ICON_OUTLINER_OB_LIGHT; + break; + case OB_MESH: + data.icon = ICON_OUTLINER_OB_MESH; + break; + case OB_CAMERA: + data.icon = ICON_OUTLINER_OB_CAMERA; + break; + case OB_CURVE: + data.icon = ICON_OUTLINER_OB_CURVE; + break; + case OB_MBALL: + data.icon = ICON_OUTLINER_OB_META; + break; + case OB_LATTICE: + data.icon = ICON_OUTLINER_OB_LATTICE; + break; + case OB_ARMATURE: + data.icon = ICON_OUTLINER_OB_ARMATURE; + break; + case OB_FONT: + data.icon = ICON_OUTLINER_OB_FONT; + break; + case OB_SURF: + data.icon = ICON_OUTLINER_OB_SURFACE; + break; + case OB_SPEAKER: + data.icon = ICON_OUTLINER_OB_SPEAKER; + break; + case OB_LIGHTPROBE: + data.icon = ICON_OUTLINER_OB_LIGHTPROBE; + break; + case OB_EMPTY: + if (ob->instance_collection) { + data.icon = ICON_OUTLINER_OB_GROUP_INSTANCE; + } + else if (ob->empty_drawtype == OB_EMPTY_IMAGE) { + data.icon = ICON_OUTLINER_OB_IMAGE; + } + else { + data.icon = ICON_OUTLINER_OB_EMPTY; + } + break; + case OB_GPENCIL: + data.icon = ICON_OUTLINER_OB_GREASEPENCIL; + break; + break; + } + } + else { + /* TODO(sergey): Casting to short here just to handle ID_NLA which is + * NOT inside of IDType enum. + */ + switch ((short)GS(tselem->id->name)) { + case ID_SCE: + data.icon = ICON_SCENE_DATA; + break; + case ID_ME: + data.icon = ICON_OUTLINER_DATA_MESH; + break; + case ID_CU: + data.icon = ICON_OUTLINER_DATA_CURVE; + break; + case ID_MB: + data.icon = ICON_OUTLINER_DATA_META; + break; + case ID_LT: + data.icon = ICON_OUTLINER_DATA_LATTICE; + break; + case ID_LA: { + Light *la = (Light *)tselem->id; + switch (la->type) { + case LA_LOCAL: + data.icon = ICON_LIGHT_POINT; + break; + case LA_SUN: + data.icon = ICON_LIGHT_SUN; + break; + case LA_SPOT: + data.icon = ICON_LIGHT_SPOT; + break; + case LA_AREA: + data.icon = ICON_LIGHT_AREA; + break; + default: + data.icon = ICON_OUTLINER_DATA_LIGHT; + break; + } + break; + } + case ID_MA: + data.icon = ICON_MATERIAL_DATA; + break; + case ID_TE: + data.icon = ICON_TEXTURE_DATA; + break; + case ID_IM: + data.icon = ICON_IMAGE_DATA; + break; + case ID_SPK: + case ID_SO: + data.icon = ICON_OUTLINER_DATA_SPEAKER; + break; + case ID_AR: + data.icon = ICON_OUTLINER_DATA_ARMATURE; + break; + case ID_CA: + data.icon = ICON_OUTLINER_DATA_CAMERA; + break; + case ID_KE: + data.icon = ICON_SHAPEKEY_DATA; + break; + case ID_WO: + data.icon = ICON_WORLD_DATA; + break; + case ID_AC: + data.icon = ICON_ACTION; + break; + case ID_NLA: + data.icon = ICON_NLA; + break; + case ID_TXT: + data.icon = ICON_SCRIPT; + break; + case ID_GR: + data.icon = ICON_GROUP; + break; + case ID_LI: + if (tselem->id->tag & LIB_TAG_MISSING) { + data.icon = ICON_LIBRARY_DATA_BROKEN; + } + else if (((Library *)tselem->id)->parent) { + data.icon = ICON_LIBRARY_DATA_INDIRECT; + } + else { + data.icon = ICON_LIBRARY_DATA_DIRECT; + } + break; + case ID_LS: + data.icon = ICON_LINE_DATA; + break; + case ID_GD: + data.icon = ICON_OUTLINER_DATA_GREASEPENCIL; + break; + case ID_LP: { + LightProbe *lp = (LightProbe *)tselem->id; + switch (lp->type) { + case LIGHTPROBE_TYPE_CUBE: + data.icon = ICON_LIGHTPROBE_CUBEMAP; + break; + case LIGHTPROBE_TYPE_PLANAR: + data.icon = ICON_LIGHTPROBE_PLANAR; + break; + case LIGHTPROBE_TYPE_GRID: + data.icon = ICON_LIGHTPROBE_GRID; + break; + default: + data.icon = ICON_LIGHTPROBE_CUBEMAP; + break; + } + break; + } + case ID_BR: + data.icon = ICON_BRUSH_DATA; + break; + case ID_SCR: + case ID_WS: + data.icon = ICON_WORKSPACE; + break; + case ID_MSK: + data.icon = ICON_MOD_MASK; + break; + case ID_MC: + data.icon = ICON_SEQUENCE; + break; + case ID_PC: + data.icon = ICON_CURVE_BEZCURVE; + break; + default: + break; + } + } + } + + return data; } -static void tselem_draw_icon( - uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te, - float alpha, const bool is_clickable) +static void tselem_draw_icon(uiBlock *block, + int xmax, + float x, + float y, + TreeStoreElem *tselem, + TreeElement *te, + float alpha, + const bool is_clickable) { - TreeElementIcon data = tree_element_get_icon(tselem, te); - - if (data.icon == 0) { - return; - } - - if (!is_clickable || x >= xmax) { - /* placement of icons, copied from interface_widgets.c */ - float aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT; - x += 2.0f * aspect; - y += 2.0f * aspect; - - /* restrict column clip... it has been coded by simply overdrawing, - * doesn't work for buttons */ - UI_icon_draw_alpha(x, y, data.icon, alpha); - } - else { - uiDefIconBut( - block, UI_BTYPE_LABEL, 0, data.icon, x, y, UI_UNIT_X, UI_UNIT_Y, NULL, - 0.0, 0.0, 1.0, alpha, - (data.drag_id && ID_IS_LINKED(data.drag_id)) ? data.drag_id->lib->name : ""); - } + TreeElementIcon data = tree_element_get_icon(tselem, te); + + if (data.icon == 0) { + return; + } + + if (!is_clickable || x >= xmax) { + /* placement of icons, copied from interface_widgets.c */ + float aspect = (0.8f * UI_UNIT_Y) / ICON_DEFAULT_HEIGHT; + x += 2.0f * aspect; + y += 2.0f * aspect; + + /* restrict column clip... it has been coded by simply overdrawing, + * doesn't work for buttons */ + UI_icon_draw_alpha(x, y, data.icon, alpha); + } + else { + uiDefIconBut(block, + UI_BTYPE_LABEL, + 0, + data.icon, + x, + y, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 1.0, + alpha, + (data.drag_id && ID_IS_LINKED(data.drag_id)) ? data.drag_id->lib->name : ""); + } } /** * For icon-only children of a collapsed tree, * Draw small number over the icon to show how many items of this type are displayed. */ -static void outliner_draw_iconrow_number( - const uiFontStyle *fstyle, - int offsx, int ys, - const int num_elements) +static void outliner_draw_iconrow_number(const uiFontStyle *fstyle, + int offsx, + int ys, + const int num_elements) { - float color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - float ufac = 0.25f * UI_UNIT_X; - float offset_x = (float) offsx + UI_UNIT_X * 0.35f; - - UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_aa(true, - offset_x + ufac, - (float)ys - UI_UNIT_Y * 0.2f + ufac, - offset_x + UI_UNIT_X - ufac, - (float)ys - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac, - (float)UI_UNIT_Y / 2.0f - ufac, - color); - - /* Now the numbers. */ - unsigned char text_col[4]; - - UI_GetThemeColor4ubv(TH_TEXT_HI, text_col); - text_col[3] = 255; - - uiFontStyle fstyle_small = *fstyle; - fstyle_small.points *= 0.8f; - - /* We treat +99 as 4 digits to make sure the (eyeballed) alignment looks nice. */ - int num_digits = 4; - char number_text[4] = "+99\0"; - if (num_elements < 100) { - BLI_snprintf(number_text, sizeof(number_text), "%d", num_elements); - num_digits = num_elements < 10 ? 1 : 2; - } - UI_fontstyle_draw_simple(&fstyle_small, - (offset_x + ufac + UI_UNIT_X * (2 - num_digits) * 0.12f), - (float)ys - UI_UNIT_Y * 0.095f + ufac, - number_text, text_col); - UI_fontstyle_set(fstyle); - GPU_blend(true); /* Roundbox and text drawing disables. */ + float color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + float ufac = 0.25f * UI_UNIT_X; + float offset_x = (float)offsx + UI_UNIT_X * 0.35f; + + UI_draw_roundbox_corner_set(UI_CNR_ALL); + UI_draw_roundbox_aa(true, + offset_x + ufac, + (float)ys - UI_UNIT_Y * 0.2f + ufac, + offset_x + UI_UNIT_X - ufac, + (float)ys - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac, + (float)UI_UNIT_Y / 2.0f - ufac, + color); + + /* Now the numbers. */ + unsigned char text_col[4]; + + UI_GetThemeColor4ubv(TH_TEXT_HI, text_col); + text_col[3] = 255; + + uiFontStyle fstyle_small = *fstyle; + fstyle_small.points *= 0.8f; + + /* We treat +99 as 4 digits to make sure the (eyeballed) alignment looks nice. */ + int num_digits = 4; + char number_text[4] = "+99\0"; + if (num_elements < 100) { + BLI_snprintf(number_text, sizeof(number_text), "%d", num_elements); + num_digits = num_elements < 10 ? 1 : 2; + } + UI_fontstyle_draw_simple(&fstyle_small, + (offset_x + ufac + UI_UNIT_X * (2 - num_digits) * 0.12f), + (float)ys - UI_UNIT_Y * 0.095f + ufac, + number_text, + text_col); + UI_fontstyle_set(fstyle); + GPU_blend(true); /* Roundbox and text drawing disables. */ } -static void outliner_draw_iconrow_doit( - uiBlock *block, TreeElement *te, - const uiFontStyle *fstyle, - int xmax, int *offsx, int ys, float alpha_fac, - const eOLDrawState active, - const int num_elements) +static void outliner_draw_iconrow_doit(uiBlock *block, + TreeElement *te, + const uiFontStyle *fstyle, + int xmax, + int *offsx, + int ys, + float alpha_fac, + const eOLDrawState active, + const int num_elements) { - TreeStoreElem *tselem = TREESTORE(te); - - if (active != OL_DRAWSEL_NONE) { - float ufac = UI_UNIT_X / 20.0f; - float color[4] = {1.0f, 1.0f, 1.0f, 0.2f}; - - UI_draw_roundbox_corner_set(UI_CNR_ALL); - color[3] *= alpha_fac; - - UI_draw_roundbox_aa(true, - (float) *offsx + 1.0f * ufac, - (float)ys + 1.0f * ufac, - (float)*offsx + UI_UNIT_X - 1.0f * ufac, - (float)ys + UI_UNIT_Y - ufac, - (float)UI_UNIT_Y / 2.0f - ufac, - color); - GPU_blend(true); /* Roundbox disables. */ - } - - /* No inlined icon should be clickable. */ - tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.8f * alpha_fac, false); - te->xs = *offsx; - te->ys = ys; - te->xend = (short)*offsx + UI_UNIT_X; - - if (num_elements > 1) { - outliner_draw_iconrow_number(fstyle, *offsx, ys, num_elements); - } - (*offsx) += UI_UNIT_X; + TreeStoreElem *tselem = TREESTORE(te); + + if (active != OL_DRAWSEL_NONE) { + float ufac = UI_UNIT_X / 20.0f; + float color[4] = {1.0f, 1.0f, 1.0f, 0.2f}; + + UI_draw_roundbox_corner_set(UI_CNR_ALL); + color[3] *= alpha_fac; + + UI_draw_roundbox_aa(true, + (float)*offsx + 1.0f * ufac, + (float)ys + 1.0f * ufac, + (float)*offsx + UI_UNIT_X - 1.0f * ufac, + (float)ys + UI_UNIT_Y - ufac, + (float)UI_UNIT_Y / 2.0f - ufac, + color); + GPU_blend(true); /* Roundbox disables. */ + } + + /* No inlined icon should be clickable. */ + tselem_draw_icon(block, xmax, (float)*offsx, (float)ys, tselem, te, 0.8f * alpha_fac, false); + te->xs = *offsx; + te->ys = ys; + te->xend = (short)*offsx + UI_UNIT_X; + + if (num_elements > 1) { + outliner_draw_iconrow_number(fstyle, *offsx, ys, num_elements); + } + (*offsx) += UI_UNIT_X; } /** @@ -1591,675 +1912,764 @@ static void outliner_draw_iconrow_doit( */ static int tree_element_id_type_to_index(TreeElement *te) { - TreeStoreElem *tselem = TREESTORE(te); - - const int id_index = tselem->type == 0 ? BKE_idcode_to_index(te->idcode) : INDEX_ID_GR; - if (id_index < INDEX_ID_OB) { - return id_index; - } - else if (id_index == INDEX_ID_OB) { - const Object *ob = (Object *)tselem->id; - return INDEX_ID_OB + ob->type; - } - else { - return id_index + OB_TYPE_MAX; - } + TreeStoreElem *tselem = TREESTORE(te); + + const int id_index = tselem->type == 0 ? BKE_idcode_to_index(te->idcode) : INDEX_ID_GR; + if (id_index < INDEX_ID_OB) { + return id_index; + } + else if (id_index == INDEX_ID_OB) { + const Object *ob = (Object *)tselem->id; + return INDEX_ID_OB + ob->type; + } + else { + return id_index + OB_TYPE_MAX; + } } typedef struct MergedIconRow { - eOLDrawState active[INDEX_ID_MAX + OB_TYPE_MAX]; - int num_elements[INDEX_ID_MAX + OB_TYPE_MAX]; - TreeElement *tree_element[INDEX_ID_MAX + OB_TYPE_MAX]; + eOLDrawState active[INDEX_ID_MAX + OB_TYPE_MAX]; + int num_elements[INDEX_ID_MAX + OB_TYPE_MAX]; + TreeElement *tree_element[INDEX_ID_MAX + OB_TYPE_MAX]; } MergedIconRow; -static void outliner_draw_iconrow( - bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, ViewLayer *view_layer, SpaceOutliner *soops, - ListBase *lb, int level, int xmax, int *offsx, int ys, float alpha_fac, MergedIconRow *merged) +static void outliner_draw_iconrow(bContext *C, + uiBlock *block, + const uiFontStyle *fstyle, + Scene *scene, + ViewLayer *view_layer, + SpaceOutliner *soops, + ListBase *lb, + int level, + int xmax, + int *offsx, + int ys, + float alpha_fac, + MergedIconRow *merged) { - eOLDrawState active; - const Object *obact = OBACT(view_layer); - - for (TreeElement *te = lb->first; te; te = te->next) { - /* exit drawing early */ - if ((*offsx) - UI_UNIT_X > xmax) { - break; - } - - TreeStoreElem *tselem = TREESTORE(te); - - /* object hierarchy always, further constrained on level */ - if (level < 1 || (tselem->type == 0 && te->idcode == ID_OB)) { - /* active blocks get white circle */ - if (tselem->type == 0) { - if (te->idcode == ID_OB) { - active = (OBACT(view_layer) == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE; - } - else if (is_object_data_in_editmode(tselem->id, obact)) { - active = OL_DRAWSEL_NORMAL; - } - else { - active = tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NONE, false); - } - } - else { - active = tree_element_type_active(C, scene, view_layer, soops, te, tselem, OL_SETSEL_NONE, false); - } - - if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION, TSE_R_LAYER)) { - outliner_draw_iconrow_doit(block, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1); - } - else { - const int index = tree_element_id_type_to_index(te); - merged->num_elements[index]++; - if ((merged->tree_element[index] == NULL) || - (active > merged->active[index])) - { - merged->tree_element[index] = te; - } - merged->active[index] = MAX2(active, merged->active[index]); - } - } - - /* this tree element always has same amount of branches, so don't draw */ - if (tselem->type != TSE_R_LAYER) { - outliner_draw_iconrow( - C, block, fstyle, scene, view_layer, soops, - &te->subtree, level + 1, xmax, offsx, ys, alpha_fac, merged); - } - } - - if (level == 0) { - for (int i = 0; i < INDEX_ID_MAX; i++) { - const int num_subtypes = (i == INDEX_ID_OB) ? OB_TYPE_MAX : 1; - /* See tree_element_id_type_to_index for the index logic. */ - int index_base = i; - if (i > INDEX_ID_OB) { - index_base += OB_TYPE_MAX; - } - for (int j = 0; j < num_subtypes; j++) { - const int index = index_base + j; - if (merged->num_elements[index] != 0) { - outliner_draw_iconrow_doit(block, - merged->tree_element[index], - fstyle, - xmax, offsx, ys, alpha_fac, - merged->active[index], - merged->num_elements[index]); - } - } - } - } + eOLDrawState active; + const Object *obact = OBACT(view_layer); + + for (TreeElement *te = lb->first; te; te = te->next) { + /* exit drawing early */ + if ((*offsx) - UI_UNIT_X > xmax) { + break; + } + + TreeStoreElem *tselem = TREESTORE(te); + + /* object hierarchy always, further constrained on level */ + if (level < 1 || (tselem->type == 0 && te->idcode == ID_OB)) { + /* active blocks get white circle */ + if (tselem->type == 0) { + if (te->idcode == ID_OB) { + active = (OBACT(view_layer) == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : + OL_DRAWSEL_NONE; + } + else if (is_object_data_in_editmode(tselem->id, obact)) { + active = OL_DRAWSEL_NORMAL; + } + else { + active = tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NONE, false); + } + } + else { + active = tree_element_type_active( + C, scene, view_layer, soops, te, tselem, OL_SETSEL_NONE, false); + } + + if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION, TSE_R_LAYER)) { + outliner_draw_iconrow_doit(block, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1); + } + else { + const int index = tree_element_id_type_to_index(te); + merged->num_elements[index]++; + if ((merged->tree_element[index] == NULL) || (active > merged->active[index])) { + merged->tree_element[index] = te; + } + merged->active[index] = MAX2(active, merged->active[index]); + } + } + + /* this tree element always has same amount of branches, so don't draw */ + if (tselem->type != TSE_R_LAYER) { + outliner_draw_iconrow(C, + block, + fstyle, + scene, + view_layer, + soops, + &te->subtree, + level + 1, + xmax, + offsx, + ys, + alpha_fac, + merged); + } + } + + if (level == 0) { + for (int i = 0; i < INDEX_ID_MAX; i++) { + const int num_subtypes = (i == INDEX_ID_OB) ? OB_TYPE_MAX : 1; + /* See tree_element_id_type_to_index for the index logic. */ + int index_base = i; + if (i > INDEX_ID_OB) { + index_base += OB_TYPE_MAX; + } + for (int j = 0; j < num_subtypes; j++) { + const int index = index_base + j; + if (merged->num_elements[index] != 0) { + outliner_draw_iconrow_doit(block, + merged->tree_element[index], + fstyle, + xmax, + offsx, + ys, + alpha_fac, + merged->active[index], + merged->num_elements[index]); + } + } + } + } } /* closed tree element */ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int starty) { - TreeElement *ten; - - /* closed items may be displayed in row of parent, don't change their coordinate! */ - if ((te->flag & TE_ICONROW) == 0) { - /* store coord and continue, we need coordinates for elements outside view too */ - te->xs = startx; - te->ys = starty; - } - - for (ten = te->subtree.first; ten; ten = ten->next) { - outliner_set_coord_tree_element(ten, startx + UI_UNIT_X, starty); - } + TreeElement *ten; + + /* closed items may be displayed in row of parent, don't change their coordinate! */ + if ((te->flag & TE_ICONROW) == 0) { + /* store coord and continue, we need coordinates for elements outside view too */ + te->xs = startx; + te->ys = starty; + } + + for (ten = te->subtree.first; ten; ten = ten->next) { + outliner_set_coord_tree_element(ten, startx + UI_UNIT_X, starty); + } } - -static void outliner_draw_tree_element( - bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, ViewLayer *view_layer, - ARegion *ar, SpaceOutliner *soops, TreeElement *te, bool draw_grayed_out, - int startx, int *starty, TreeElement **te_edit) +static void outliner_draw_tree_element(bContext *C, + uiBlock *block, + const uiFontStyle *fstyle, + Scene *scene, + ViewLayer *view_layer, + ARegion *ar, + SpaceOutliner *soops, + TreeElement *te, + bool draw_grayed_out, + int startx, + int *starty, + TreeElement **te_edit) { - TreeStoreElem *tselem; - float ufac = UI_UNIT_X / 20.0f; - int offsx = 0; - eOLDrawState active = OL_DRAWSEL_NONE; - float color[4]; - tselem = TREESTORE(te); - - if (*starty + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && *starty <= ar->v2d.cur.ymax) { - const float alpha_fac = ((te->flag & TE_DISABLED) || draw_grayed_out) ? 0.5f : 1.0f; - const float alpha = 0.5f * alpha_fac; - int xmax = ar->v2d.cur.xmax; - - if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == NULL)) { - *te_edit = te; - } - - /* icons can be ui buts, we don't want it to overlap with restrict */ - if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) { - xmax -= OL_TOGW + UI_UNIT_X; - } - - GPU_blend(true); - - /* colors for active/selected data */ - if (tselem->type == 0) { - const Object *obact = OBACT(view_layer); - if (te->idcode == ID_SCE) { - if (tselem->id == (ID *)scene) { - rgba_float_args_set(color, 1.0f, 1.0f, 1.0f, alpha); - active = OL_DRAWSEL_ACTIVE; - } - } - else if (te->idcode == ID_OB) { - Object *ob = (Object *)tselem->id; - Base *base = BKE_view_layer_base_find(view_layer, ob); - const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0); - - if (ob == obact || is_selected) { - uchar col[4] = {0, 0, 0, 0}; - - /* outliner active ob: always white text, circle color now similar to view3d */ - - active = OL_DRAWSEL_ACTIVE; - if (ob == obact) { - if (is_selected) { - UI_GetThemeColorType4ubv(TH_ACTIVE, SPACE_VIEW3D, col); - col[3] = alpha; - } - - active = OL_DRAWSEL_NORMAL; - } - else if (is_selected) { - UI_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col); - col[3] = alpha; - } - rgba_float_args_set(color, (float)col[0] / 255, (float)col[1] / 255, (float)col[2] / 255, alpha); - } - } - else if (is_object_data_in_editmode(tselem->id, obact)) { - rgba_float_args_set(color, 1.0f, 1.0f, 1.0f, alpha); - active = OL_DRAWSEL_ACTIVE; - } - else { - if (tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NONE, false)) { - rgba_float_args_set(color, 0.85f, 0.85f, 1.0f, alpha); - active = OL_DRAWSEL_ACTIVE; - } - } - } - else { - active = tree_element_type_active(C, scene, view_layer, soops, te, tselem, OL_SETSEL_NONE, false); - rgba_float_args_set(color, 0.85f, 0.85f, 1.0f, alpha); - } - - /* active circle */ - if (active != OL_DRAWSEL_NONE) { - UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_aa( - true, - (float)startx + UI_UNIT_X + 1.0f * ufac, - (float)*starty + 1.0f * ufac, - (float)startx + 2.0f * UI_UNIT_X - 1.0f * ufac, - (float)*starty + UI_UNIT_Y - 1.0f * ufac, - UI_UNIT_Y / 2.0f - 1.0f * ufac, color); - GPU_blend(true); /* roundbox disables it */ - - te->flag |= TE_ACTIVE; // for lookup in display hierarchies - } - - if (tselem->type == TSE_VIEW_COLLECTION_BASE) { - /* Scene collection in view layer can't expand/collapse. */ - } - else if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || (te->flag & TE_LAZY_CLOSED)) { - /* open/close icon, only when sublevels, except for scene */ - int icon_x = startx; - - // icons a bit higher - if (TSELEM_OPEN(tselem, soops)) { - UI_icon_draw_alpha( - (float)icon_x + 2 * ufac, (float)*starty + 1 * ufac, ICON_DISCLOSURE_TRI_DOWN, - alpha_fac); - } - else { - UI_icon_draw_alpha( - (float)icon_x + 2 * ufac, (float)*starty + 1 * ufac, ICON_DISCLOSURE_TRI_RIGHT, - alpha_fac); - } - } - offsx += UI_UNIT_X; - - /* datatype icon */ - - if (!(ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE))) { - tselem_draw_icon(block, xmax, (float)startx + offsx, (float)*starty, tselem, te, alpha_fac, true); - offsx += UI_UNIT_X + 4 * ufac; - } - else { - offsx += 2 * ufac; - } - - if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION) && ID_IS_LINKED(tselem->id)) { - if (tselem->id->tag & LIB_TAG_MISSING) { - UI_icon_draw_alpha( - (float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN, - alpha_fac); - } - else if (tselem->id->tag & LIB_TAG_INDIRECT) { - UI_icon_draw_alpha( - (float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_INDIRECT, - alpha_fac); - } - else { - UI_icon_draw_alpha( - (float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_DIRECT, - alpha_fac); - } - offsx += UI_UNIT_X + 4 * ufac; - } - else if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION) && ID_IS_STATIC_OVERRIDE(tselem->id)) { - UI_icon_draw_alpha( - (float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_OVERRIDE, - alpha_fac); - offsx += UI_UNIT_X + 4 * ufac; - } - GPU_blend(false); - - /* name */ - if ((tselem->flag & TSE_TEXTBUT) == 0) { - unsigned char text_col[4]; - - if (active == OL_DRAWSEL_NORMAL) { - UI_GetThemeColor4ubv(TH_TEXT_HI, text_col); - } - else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { - UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.75f, text_col); - text_col[3] = 255; - } - else { - UI_GetThemeColor4ubv(TH_TEXT, text_col); - } - text_col[3] *= alpha_fac; - - UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name, text_col); - } - - offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name)); - - /* closed item, we draw the icons, not when it's a scene, or master-server list though */ - if (!TSELEM_OPEN(tselem, soops)) { - if (te->subtree.first) { - if (tselem->type == 0 && te->idcode == ID_SCE) { - /* pass */ - } - /* this tree element always has same amount of branches, so don't draw */ - else if (tselem->type != TSE_R_LAYER) { - int tempx = startx + offsx; - - GPU_blend(true); - - /* divider */ - { - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); - unsigned char col[4]; - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - UI_GetThemeColorShade4ubv(TH_BACK, -40, col); - col[3] *= alpha_fac; - - immUniformColor4ubv(col); - immRecti(pos, tempx - 10.0f * ufac, - *starty + 4.0f * ufac, - tempx - 8.0f * ufac, - *starty + UI_UNIT_Y - 4.0f * ufac); - immUnbindProgram(); - } - - MergedIconRow merged = {{0}}; - outliner_draw_iconrow( - C, block, fstyle, scene, view_layer, soops, &te->subtree, 0, xmax, &tempx, - *starty, alpha_fac, &merged); - - GPU_blend(false); - } - } - } - } - /* store coord and continue, we need coordinates for elements outside view too */ - te->xs = startx; - te->ys = *starty; - te->xend = startx + offsx; - - if (TSELEM_OPEN(tselem, soops)) { - *starty -= UI_UNIT_Y; - - for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) { - /* check if element needs to be drawn grayed out, but also gray out - * childs of a grayed out parent (pass on draw_grayed_out to childs) */ - bool draw_childs_grayed_out = draw_grayed_out || (ten->flag & TE_DRAGGING); - outliner_draw_tree_element( - C, block, fstyle, scene, view_layer, - ar, soops, ten, draw_childs_grayed_out, - startx + UI_UNIT_X, starty, te_edit); - } - } - else { - for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) { - outliner_set_coord_tree_element(ten, startx, *starty); - } - - *starty -= UI_UNIT_Y; - } + TreeStoreElem *tselem; + float ufac = UI_UNIT_X / 20.0f; + int offsx = 0; + eOLDrawState active = OL_DRAWSEL_NONE; + float color[4]; + tselem = TREESTORE(te); + + if (*starty + 2 * UI_UNIT_Y >= ar->v2d.cur.ymin && *starty <= ar->v2d.cur.ymax) { + const float alpha_fac = ((te->flag & TE_DISABLED) || draw_grayed_out) ? 0.5f : 1.0f; + const float alpha = 0.5f * alpha_fac; + int xmax = ar->v2d.cur.xmax; + + if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == NULL)) { + *te_edit = te; + } + + /* icons can be ui buts, we don't want it to overlap with restrict */ + if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) { + xmax -= OL_TOGW + UI_UNIT_X; + } + + GPU_blend(true); + + /* colors for active/selected data */ + if (tselem->type == 0) { + const Object *obact = OBACT(view_layer); + if (te->idcode == ID_SCE) { + if (tselem->id == (ID *)scene) { + rgba_float_args_set(color, 1.0f, 1.0f, 1.0f, alpha); + active = OL_DRAWSEL_ACTIVE; + } + } + else if (te->idcode == ID_OB) { + Object *ob = (Object *)tselem->id; + Base *base = BKE_view_layer_base_find(view_layer, ob); + const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0); + + if (ob == obact || is_selected) { + uchar col[4] = {0, 0, 0, 0}; + + /* outliner active ob: always white text, circle color now similar to view3d */ + + active = OL_DRAWSEL_ACTIVE; + if (ob == obact) { + if (is_selected) { + UI_GetThemeColorType4ubv(TH_ACTIVE, SPACE_VIEW3D, col); + col[3] = alpha; + } + + active = OL_DRAWSEL_NORMAL; + } + else if (is_selected) { + UI_GetThemeColorType4ubv(TH_SELECT, SPACE_VIEW3D, col); + col[3] = alpha; + } + rgba_float_args_set( + color, (float)col[0] / 255, (float)col[1] / 255, (float)col[2] / 255, alpha); + } + } + else if (is_object_data_in_editmode(tselem->id, obact)) { + rgba_float_args_set(color, 1.0f, 1.0f, 1.0f, alpha); + active = OL_DRAWSEL_ACTIVE; + } + else { + if (tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NONE, false)) { + rgba_float_args_set(color, 0.85f, 0.85f, 1.0f, alpha); + active = OL_DRAWSEL_ACTIVE; + } + } + } + else { + active = tree_element_type_active( + C, scene, view_layer, soops, te, tselem, OL_SETSEL_NONE, false); + rgba_float_args_set(color, 0.85f, 0.85f, 1.0f, alpha); + } + + /* active circle */ + if (active != OL_DRAWSEL_NONE) { + UI_draw_roundbox_corner_set(UI_CNR_ALL); + UI_draw_roundbox_aa(true, + (float)startx + UI_UNIT_X + 1.0f * ufac, + (float)*starty + 1.0f * ufac, + (float)startx + 2.0f * UI_UNIT_X - 1.0f * ufac, + (float)*starty + UI_UNIT_Y - 1.0f * ufac, + UI_UNIT_Y / 2.0f - 1.0f * ufac, + color); + GPU_blend(true); /* roundbox disables it */ + + te->flag |= TE_ACTIVE; // for lookup in display hierarchies + } + + if (tselem->type == TSE_VIEW_COLLECTION_BASE) { + /* Scene collection in view layer can't expand/collapse. */ + } + else if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || + (te->flag & TE_LAZY_CLOSED)) { + /* open/close icon, only when sublevels, except for scene */ + int icon_x = startx; + + // icons a bit higher + if (TSELEM_OPEN(tselem, soops)) { + UI_icon_draw_alpha((float)icon_x + 2 * ufac, + (float)*starty + 1 * ufac, + ICON_DISCLOSURE_TRI_DOWN, + alpha_fac); + } + else { + UI_icon_draw_alpha((float)icon_x + 2 * ufac, + (float)*starty + 1 * ufac, + ICON_DISCLOSURE_TRI_RIGHT, + alpha_fac); + } + } + offsx += UI_UNIT_X; + + /* datatype icon */ + + if (!(ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE))) { + tselem_draw_icon( + block, xmax, (float)startx + offsx, (float)*starty, tselem, te, alpha_fac, true); + offsx += UI_UNIT_X + 4 * ufac; + } + else { + offsx += 2 * ufac; + } + + if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION) && ID_IS_LINKED(tselem->id)) { + if (tselem->id->tag & LIB_TAG_MISSING) { + UI_icon_draw_alpha((float)startx + offsx + 2 * ufac, + (float)*starty + 2 * ufac, + ICON_LIBRARY_DATA_BROKEN, + alpha_fac); + } + else if (tselem->id->tag & LIB_TAG_INDIRECT) { + UI_icon_draw_alpha((float)startx + offsx + 2 * ufac, + (float)*starty + 2 * ufac, + ICON_LIBRARY_DATA_INDIRECT, + alpha_fac); + } + else { + UI_icon_draw_alpha((float)startx + offsx + 2 * ufac, + (float)*starty + 2 * ufac, + ICON_LIBRARY_DATA_DIRECT, + alpha_fac); + } + offsx += UI_UNIT_X + 4 * ufac; + } + else if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION) && ID_IS_STATIC_OVERRIDE(tselem->id)) { + UI_icon_draw_alpha((float)startx + offsx + 2 * ufac, + (float)*starty + 2 * ufac, + ICON_LIBRARY_DATA_OVERRIDE, + alpha_fac); + offsx += UI_UNIT_X + 4 * ufac; + } + GPU_blend(false); + + /* name */ + if ((tselem->flag & TSE_TEXTBUT) == 0) { + unsigned char text_col[4]; + + if (active == OL_DRAWSEL_NORMAL) { + UI_GetThemeColor4ubv(TH_TEXT_HI, text_col); + } + else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { + UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.75f, text_col); + text_col[3] = 255; + } + else { + UI_GetThemeColor4ubv(TH_TEXT, text_col); + } + text_col[3] *= alpha_fac; + + UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name, text_col); + } + + offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name)); + + /* closed item, we draw the icons, not when it's a scene, or master-server list though */ + if (!TSELEM_OPEN(tselem, soops)) { + if (te->subtree.first) { + if (tselem->type == 0 && te->idcode == ID_SCE) { + /* pass */ + } + /* this tree element always has same amount of branches, so don't draw */ + else if (tselem->type != TSE_R_LAYER) { + int tempx = startx + offsx; + + GPU_blend(true); + + /* divider */ + { + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add( + format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); + unsigned char col[4]; + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + UI_GetThemeColorShade4ubv(TH_BACK, -40, col); + col[3] *= alpha_fac; + + immUniformColor4ubv(col); + immRecti(pos, + tempx - 10.0f * ufac, + *starty + 4.0f * ufac, + tempx - 8.0f * ufac, + *starty + UI_UNIT_Y - 4.0f * ufac); + immUnbindProgram(); + } + + MergedIconRow merged = {{0}}; + outliner_draw_iconrow(C, + block, + fstyle, + scene, + view_layer, + soops, + &te->subtree, + 0, + xmax, + &tempx, + *starty, + alpha_fac, + &merged); + + GPU_blend(false); + } + } + } + } + /* store coord and continue, we need coordinates for elements outside view too */ + te->xs = startx; + te->ys = *starty; + te->xend = startx + offsx; + + if (TSELEM_OPEN(tselem, soops)) { + *starty -= UI_UNIT_Y; + + for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) { + /* check if element needs to be drawn grayed out, but also gray out + * childs of a grayed out parent (pass on draw_grayed_out to childs) */ + bool draw_childs_grayed_out = draw_grayed_out || (ten->flag & TE_DRAGGING); + outliner_draw_tree_element(C, + block, + fstyle, + scene, + view_layer, + ar, + soops, + ten, + draw_childs_grayed_out, + startx + UI_UNIT_X, + starty, + te_edit); + } + } + else { + for (TreeElement *ten = te->subtree.first; ten; ten = ten->next) { + outliner_set_coord_tree_element(ten, startx, *starty); + } + + *starty -= UI_UNIT_Y; + } } -static void outliner_draw_hierarchy_lines_recursive( - unsigned pos, SpaceOutliner *soops, ListBase *lb, int startx, - const unsigned char col[4], bool draw_grayed_out, - int *starty) +static void outliner_draw_hierarchy_lines_recursive(unsigned pos, + SpaceOutliner *soops, + ListBase *lb, + int startx, + const unsigned char col[4], + bool draw_grayed_out, + int *starty) { - TreeElement *te, *te_vertical_line_last = NULL; - int y1, y2; - - if (BLI_listbase_is_empty(lb)) { - return; - } - - const unsigned char grayed_alpha = col[3] / 2; - - /* For vertical lines between objects. */ - y1 = y2 = *starty; - for (te = lb->first; te; te = te->next) { - bool draw_childs_grayed_out = draw_grayed_out || (te->flag & TE_DRAGGING); - TreeStoreElem *tselem = TREESTORE(te); - - if (draw_childs_grayed_out) { - immUniformColor3ubvAlpha(col, grayed_alpha); - } - else { - immUniformColor4ubv(col); - } - - /* Horizontal Line? */ - if (tselem->type == 0 && (te->idcode == ID_OB || te->idcode == ID_SCE)) { - immRecti(pos, startx, *starty, startx + UI_UNIT_X, *starty - 1); - - /* Vertical Line? */ - if (te->idcode == ID_OB) { - te_vertical_line_last = te; - y2 = *starty; - } - } - - *starty -= UI_UNIT_Y; - - if (TSELEM_OPEN(tselem, soops)) { - outliner_draw_hierarchy_lines_recursive( - pos, soops, &te->subtree, startx + UI_UNIT_X, - col, draw_childs_grayed_out, starty); - } - } - - if (draw_grayed_out) { - immUniformColor3ubvAlpha(col, grayed_alpha); - } - else { - immUniformColor4ubv(col); - } - - /* Vertical line. */ - te = te_vertical_line_last; - if ((te != NULL) && (te->parent || lb->first != lb->last)) { - immRecti(pos, startx, y1 + UI_UNIT_Y, startx + 1, y2); - } + TreeElement *te, *te_vertical_line_last = NULL; + int y1, y2; + + if (BLI_listbase_is_empty(lb)) { + return; + } + + const unsigned char grayed_alpha = col[3] / 2; + + /* For vertical lines between objects. */ + y1 = y2 = *starty; + for (te = lb->first; te; te = te->next) { + bool draw_childs_grayed_out = draw_grayed_out || (te->flag & TE_DRAGGING); + TreeStoreElem *tselem = TREESTORE(te); + + if (draw_childs_grayed_out) { + immUniformColor3ubvAlpha(col, grayed_alpha); + } + else { + immUniformColor4ubv(col); + } + + /* Horizontal Line? */ + if (tselem->type == 0 && (te->idcode == ID_OB || te->idcode == ID_SCE)) { + immRecti(pos, startx, *starty, startx + UI_UNIT_X, *starty - 1); + + /* Vertical Line? */ + if (te->idcode == ID_OB) { + te_vertical_line_last = te; + y2 = *starty; + } + } + + *starty -= UI_UNIT_Y; + + if (TSELEM_OPEN(tselem, soops)) { + outliner_draw_hierarchy_lines_recursive( + pos, soops, &te->subtree, startx + UI_UNIT_X, col, draw_childs_grayed_out, starty); + } + } + + if (draw_grayed_out) { + immUniformColor3ubvAlpha(col, grayed_alpha); + } + else { + immUniformColor4ubv(col); + } + + /* Vertical line. */ + te = te_vertical_line_last; + if ((te != NULL) && (te->parent || lb->first != lb->last)) { + immRecti(pos, startx, y1 + UI_UNIT_Y, startx + 1, y2); + } } -static void outliner_draw_hierarchy_lines(SpaceOutliner *soops, ListBase *lb, int startx, int *starty) +static void outliner_draw_hierarchy_lines(SpaceOutliner *soops, + ListBase *lb, + int startx, + int *starty) { - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); - unsigned char col[4]; + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); + unsigned char col[4]; - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.4f, col); - col[3] = 255; + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.4f, col); + col[3] = 255; - GPU_blend(true); - outliner_draw_hierarchy_lines_recursive(pos, soops, lb, startx, col, false, starty); - GPU_blend(false); + GPU_blend(true); + outliner_draw_hierarchy_lines_recursive(pos, soops, lb, startx, col, false, starty); + GPU_blend(false); - immUnbindProgram(); + immUnbindProgram(); } -static void outliner_draw_struct_marks(ARegion *ar, SpaceOutliner *soops, ListBase *lb, int *starty) +static void outliner_draw_struct_marks(ARegion *ar, + SpaceOutliner *soops, + ListBase *lb, + int *starty) { - for (TreeElement *te = lb->first; te; te = te->next) { - TreeStoreElem *tselem = TREESTORE(te); - - /* selection status */ - if (TSELEM_OPEN(tselem, soops)) { - if (tselem->type == TSE_RNA_STRUCT) { - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immThemeColorShadeAlpha(TH_BACK, -15, -200); - immRecti(pos, 0, *starty + 1, (int)ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1); - immUnbindProgram(); - } - } - - *starty -= UI_UNIT_Y; - if (TSELEM_OPEN(tselem, soops)) { - outliner_draw_struct_marks(ar, soops, &te->subtree, starty); - if (tselem->type == TSE_RNA_STRUCT) { - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immThemeColorShadeAlpha(TH_BACK, -15, -200); - - immBegin(GPU_PRIM_LINES, 2); - immVertex2f(pos, 0, (float)*starty + UI_UNIT_Y); - immVertex2f(pos, ar->v2d.cur.xmax, (float)*starty + UI_UNIT_Y); - immEnd(); - - immUnbindProgram(); - } - } - } + for (TreeElement *te = lb->first; te; te = te->next) { + TreeStoreElem *tselem = TREESTORE(te); + + /* selection status */ + if (TSELEM_OPEN(tselem, soops)) { + if (tselem->type == TSE_RNA_STRUCT) { + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immThemeColorShadeAlpha(TH_BACK, -15, -200); + immRecti(pos, 0, *starty + 1, (int)ar->v2d.cur.xmax, *starty + UI_UNIT_Y - 1); + immUnbindProgram(); + } + } + + *starty -= UI_UNIT_Y; + if (TSELEM_OPEN(tselem, soops)) { + outliner_draw_struct_marks(ar, soops, &te->subtree, starty); + if (tselem->type == TSE_RNA_STRUCT) { + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immThemeColorShadeAlpha(TH_BACK, -15, -200); + + immBegin(GPU_PRIM_LINES, 2); + immVertex2f(pos, 0, (float)*starty + UI_UNIT_Y); + immVertex2f(pos, ar->v2d.cur.xmax, (float)*starty + UI_UNIT_Y); + immEnd(); + + immUnbindProgram(); + } + } + } } -static void outliner_draw_highlights_recursive( - unsigned pos, const ARegion *ar, const SpaceOutliner *soops, const ListBase *lb, - const float col_selection[4], const float col_highlight[4], const float col_searchmatch[4], - int start_x, int *io_start_y) +static void outliner_draw_highlights_recursive(unsigned pos, + const ARegion *ar, + const SpaceOutliner *soops, + const ListBase *lb, + const float col_selection[4], + const float col_highlight[4], + const float col_searchmatch[4], + int start_x, + int *io_start_y) { - const bool is_searching = ( - SEARCHING_OUTLINER(soops) || - (soops->outlinevis == SO_DATA_API && - soops->search_string[0] != 0)); - - for (TreeElement *te = lb->first; te; te = te->next) { - const TreeStoreElem *tselem = TREESTORE(te); - const int start_y = *io_start_y; - - /* selection status */ - if (tselem->flag & TSE_SELECTED) { - immUniformColor4fv(col_selection); - immRecti(pos, 0, start_y + 1, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1); - } - - /* highlights */ - if (tselem->flag & (TSE_DRAG_ANY | TSE_HIGHLIGHTED | TSE_SEARCHMATCH)) { - const int end_x = (int)ar->v2d.cur.xmax; - - if (tselem->flag & TSE_DRAG_ANY) { - /* drag and drop highlight */ - float col[4]; - UI_GetThemeColorShade4fv(TH_BACK, -40, col); - - if (tselem->flag & TSE_DRAG_BEFORE) { - immUniformColor4fv(col); - immRecti(pos, start_x, start_y + UI_UNIT_Y - 1, end_x, start_y + UI_UNIT_Y + 1); - } - else if (tselem->flag & TSE_DRAG_AFTER) { - immUniformColor4fv(col); - immRecti(pos, start_x, start_y - 1, end_x, start_y + 1); - } - else { - immUniformColor3fvAlpha(col, col[3] * 0.5f); - immRecti(pos, start_x, start_y + 1, end_x, start_y + UI_UNIT_Y - 1); - } - } - else { - if (is_searching && (tselem->flag & TSE_SEARCHMATCH)) { - /* search match highlights - * we don't expand items when searching in the datablocks but we - * still want to highlight any filter matches. */ - immUniformColor4fv(col_searchmatch); - immRecti(pos, start_x, start_y + 1, end_x, start_y + UI_UNIT_Y - 1); - } - else if (tselem->flag & TSE_HIGHLIGHTED) { - /* mouse hover highlight */ - immUniformColor4fv(col_highlight); - immRecti(pos, 0, start_y + 1, end_x, start_y + UI_UNIT_Y - 1); - } - } - } - - *io_start_y -= UI_UNIT_Y; - if (TSELEM_OPEN(tselem, soops)) { - outliner_draw_highlights_recursive( - pos, ar, soops, &te->subtree, col_selection, col_highlight, col_searchmatch, - start_x + UI_UNIT_X, io_start_y); - } - } + const bool is_searching = (SEARCHING_OUTLINER(soops) || + (soops->outlinevis == SO_DATA_API && soops->search_string[0] != 0)); + + for (TreeElement *te = lb->first; te; te = te->next) { + const TreeStoreElem *tselem = TREESTORE(te); + const int start_y = *io_start_y; + + /* selection status */ + if (tselem->flag & TSE_SELECTED) { + immUniformColor4fv(col_selection); + immRecti(pos, 0, start_y + 1, (int)ar->v2d.cur.xmax, start_y + UI_UNIT_Y - 1); + } + + /* highlights */ + if (tselem->flag & (TSE_DRAG_ANY | TSE_HIGHLIGHTED | TSE_SEARCHMATCH)) { + const int end_x = (int)ar->v2d.cur.xmax; + + if (tselem->flag & TSE_DRAG_ANY) { + /* drag and drop highlight */ + float col[4]; + UI_GetThemeColorShade4fv(TH_BACK, -40, col); + + if (tselem->flag & TSE_DRAG_BEFORE) { + immUniformColor4fv(col); + immRecti(pos, start_x, start_y + UI_UNIT_Y - 1, end_x, start_y + UI_UNIT_Y + 1); + } + else if (tselem->flag & TSE_DRAG_AFTER) { + immUniformColor4fv(col); + immRecti(pos, start_x, start_y - 1, end_x, start_y + 1); + } + else { + immUniformColor3fvAlpha(col, col[3] * 0.5f); + immRecti(pos, start_x, start_y + 1, end_x, start_y + UI_UNIT_Y - 1); + } + } + else { + if (is_searching && (tselem->flag & TSE_SEARCHMATCH)) { + /* search match highlights + * we don't expand items when searching in the datablocks but we + * still want to highlight any filter matches. */ + immUniformColor4fv(col_searchmatch); + immRecti(pos, start_x, start_y + 1, end_x, start_y + UI_UNIT_Y - 1); + } + else if (tselem->flag & TSE_HIGHLIGHTED) { + /* mouse hover highlight */ + immUniformColor4fv(col_highlight); + immRecti(pos, 0, start_y + 1, end_x, start_y + UI_UNIT_Y - 1); + } + } + } + + *io_start_y -= UI_UNIT_Y; + if (TSELEM_OPEN(tselem, soops)) { + outliner_draw_highlights_recursive(pos, + ar, + soops, + &te->subtree, + col_selection, + col_highlight, + col_searchmatch, + start_x + UI_UNIT_X, + io_start_y); + } + } } static void outliner_draw_highlights(ARegion *ar, SpaceOutliner *soops, int startx, int *starty) { - const float col_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f}; - float col_selection[4], col_searchmatch[4]; - - UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, col_selection); - col_selection[3] = 1.0f; /* no alpha */ - UI_GetThemeColor4fv(TH_MATCH, col_searchmatch); - col_searchmatch[3] = 0.5f; - - GPU_blend(true); - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - outliner_draw_highlights_recursive( - pos, ar, soops, &soops->tree, col_selection, col_highlight, col_searchmatch, - startx, starty); - immUnbindProgram(); - GPU_blend(false); + const float col_highlight[4] = {1.0f, 1.0f, 1.0f, 0.13f}; + float col_selection[4], col_searchmatch[4]; + + UI_GetThemeColor3fv(TH_SELECT_HIGHLIGHT, col_selection); + col_selection[3] = 1.0f; /* no alpha */ + UI_GetThemeColor4fv(TH_MATCH, col_searchmatch); + col_searchmatch[3] = 0.5f; + + GPU_blend(true); + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + outliner_draw_highlights_recursive( + pos, ar, soops, &soops->tree, col_selection, col_highlight, col_searchmatch, startx, starty); + immUnbindProgram(); + GPU_blend(false); } -static void outliner_draw_tree( - bContext *C, uiBlock *block, Scene *scene, ViewLayer *view_layer, - ARegion *ar, SpaceOutliner *soops, const bool has_restrict_icons, - TreeElement **te_edit) +static void outliner_draw_tree(bContext *C, + uiBlock *block, + Scene *scene, + ViewLayer *view_layer, + ARegion *ar, + SpaceOutliner *soops, + const bool has_restrict_icons, + TreeElement **te_edit) { - const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - int starty, startx; - - GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); // only once - - if (soops->outlinevis == SO_DATA_API) { - /* struct marks */ - starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; - outliner_draw_struct_marks(ar, soops, &soops->tree, &starty); - } - - /* draw highlights before hierarchy */ - starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; - startx = 0; - outliner_draw_highlights(ar, soops, startx, &starty); - - /* set scissor so tree elements or lines can't overlap restriction icons */ - float scissor[4] = {0}; - if (has_restrict_icons) { - int mask_x = BLI_rcti_size_x(&ar->v2d.mask) - (int)OL_TOGW + 1; - CLAMP_MIN(mask_x, 0); - - GPU_scissor_get_f(scissor); - GPU_scissor(0, 0, mask_x, ar->winy); - } - - // gray hierarchy lines - - starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y / 2 - OL_Y_OFFSET; - startx = UI_UNIT_X / 2 - 1.0f; - outliner_draw_hierarchy_lines(soops, &soops->tree, startx, &starty); - - // items themselves - starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; - startx = 0; - for (TreeElement *te = soops->tree.first; te; te = te->next) { - outliner_draw_tree_element( - C, block, fstyle, scene, view_layer, - ar, soops, te, (te->flag & TE_DRAGGING) != 0, - startx, &starty, te_edit); - } - - if (has_restrict_icons) { - /* reset scissor */ - GPU_scissor(UNPACK4(scissor)); - } + const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; + int starty, startx; + + GPU_blend_set_func_separate( + GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); // only once + + if (soops->outlinevis == SO_DATA_API) { + /* struct marks */ + starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; + outliner_draw_struct_marks(ar, soops, &soops->tree, &starty); + } + + /* draw highlights before hierarchy */ + starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; + startx = 0; + outliner_draw_highlights(ar, soops, startx, &starty); + + /* set scissor so tree elements or lines can't overlap restriction icons */ + float scissor[4] = {0}; + if (has_restrict_icons) { + int mask_x = BLI_rcti_size_x(&ar->v2d.mask) - (int)OL_TOGW + 1; + CLAMP_MIN(mask_x, 0); + + GPU_scissor_get_f(scissor); + GPU_scissor(0, 0, mask_x, ar->winy); + } + + // gray hierarchy lines + + starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y / 2 - OL_Y_OFFSET; + startx = UI_UNIT_X / 2 - 1.0f; + outliner_draw_hierarchy_lines(soops, &soops->tree, startx, &starty); + + // items themselves + starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; + startx = 0; + for (TreeElement *te = soops->tree.first; te; te = te->next) { + outliner_draw_tree_element(C, + block, + fstyle, + scene, + view_layer, + ar, + soops, + te, + (te->flag & TE_DRAGGING) != 0, + startx, + &starty, + te_edit); + } + + if (has_restrict_icons) { + /* reset scissor */ + GPU_scissor(UNPACK4(scissor)); + } } - static void outliner_back(ARegion *ar) { - int ystart; - - ystart = (int)ar->v2d.tot.ymax; - ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET; - - GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformThemeColorShade(TH_BACK, 6); - - const float x1 = 0.0f, x2 = ar->v2d.cur.xmax; - float y1 = ystart, y2; - int tot = (int)floor(ystart - ar->v2d.cur.ymin + 2 * UI_UNIT_Y) / (2 * UI_UNIT_Y); - - if (tot > 0) { - immBegin(GPU_PRIM_TRIS, 6 * tot); - while (tot--) { - y1 -= 2 * UI_UNIT_Y; - y2 = y1 + UI_UNIT_Y; - immVertex2f(pos, x1, y1); - immVertex2f(pos, x2, y1); - immVertex2f(pos, x2, y2); - - immVertex2f(pos, x1, y1); - immVertex2f(pos, x2, y2); - immVertex2f(pos, x1, y2); - } - immEnd(); - } - immUnbindProgram(); + int ystart; + + ystart = (int)ar->v2d.tot.ymax; + ystart = UI_UNIT_Y * (ystart / (UI_UNIT_Y)) - OL_Y_OFFSET; + + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColorShade(TH_BACK, 6); + + const float x1 = 0.0f, x2 = ar->v2d.cur.xmax; + float y1 = ystart, y2; + int tot = (int)floor(ystart - ar->v2d.cur.ymin + 2 * UI_UNIT_Y) / (2 * UI_UNIT_Y); + + if (tot > 0) { + immBegin(GPU_PRIM_TRIS, 6 * tot); + while (tot--) { + y1 -= 2 * UI_UNIT_Y; + y2 = y1 + UI_UNIT_Y; + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y1); + immVertex2f(pos, x2, y2); + + immVertex2f(pos, x1, y1); + immVertex2f(pos, x2, y2); + immVertex2f(pos, x1, y2); + } + immEnd(); + } + immUnbindProgram(); } static void outliner_draw_restrictcols(ARegion *ar) { - GPU_line_width(1.0f); + GPU_line_width(1.0f); - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformThemeColorShadeAlpha(TH_BACK, -15, -200); - immBegin(GPU_PRIM_LINES, 6); + uint pos = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColorShadeAlpha(TH_BACK, -15, -200); + immBegin(GPU_PRIM_LINES, 6); - immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)ar->v2d.cur.ymax); - immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)ar->v2d.cur.ymin); + immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)ar->v2d.cur.ymax); + immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), (int)ar->v2d.cur.ymin); - immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)ar->v2d.cur.ymax); - immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)ar->v2d.cur.ymin); + immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)ar->v2d.cur.ymax); + immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), (int)ar->v2d.cur.ymin); - immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)ar->v2d.cur.ymax); - immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)ar->v2d.cur.ymin); + immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)ar->v2d.cur.ymax); + immVertex2i(pos, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_RENDERX), (int)ar->v2d.cur.ymin); - immEnd(); - immUnbindProgram(); + immEnd(); + immUnbindProgram(); } /* ****************************************************** */ @@ -2267,106 +2677,105 @@ static void outliner_draw_restrictcols(ARegion *ar) void draw_outliner(const bContext *C) { - Main *mainvar = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - ARegion *ar = CTX_wm_region(C); - View2D *v2d = &ar->v2d; - SpaceOutliner *soops = CTX_wm_space_outliner(C); - uiBlock *block; - int sizey = 0, sizex = 0, sizex_rna = 0; - TreeElement *te_edit = NULL; - bool has_restrict_icons; - - outliner_build_tree(mainvar, scene, view_layer, soops, ar); // always - - /* get extents of data */ - outliner_height(soops, &soops->tree, &sizey); - - /* extend size to allow for horizontal scrollbar */ - sizey += V2D_SCROLL_HEIGHT; - - if (soops->outlinevis == SO_DATA_API) { - /* RNA has two columns: - * - column 1 is (max_width + OL_RNA_COL_SPACEX) or - * (OL_RNA_COL_X), whichever is wider... - * - column 2 is fixed at OL_RNA_COL_SIZEX - * - * (*) XXX max width for now is a fixed factor of (UI_UNIT_X * (max_indention + 100)) - */ - - /* get actual width of column 1 */ - outliner_rna_width(soops, &soops->tree, &sizex_rna, 0); - sizex_rna = max_ii(OL_RNA_COLX, sizex_rna + OL_RNA_COL_SPACEX); - - /* get width of data (for setting 'tot' rect, this is column 1 + column 2 + a bit extra) */ - sizex = sizex_rna + OL_RNA_COL_SIZEX + 50; - has_restrict_icons = false; - } - else { - /* width must take into account restriction columns (if visible) - * so that entries will still be visible */ - //outliner_width(soops, &soops->tree, &sizex); - // XXX should use outliner_width instead when te->xend will be set correctly... - outliner_rna_width(soops, &soops->tree, &sizex, 0); - - /* constant offset for restriction columns */ - // XXX this isn't that great yet... - if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) { - sizex += OL_TOGW * 3; - } - - has_restrict_icons = !(soops->flag & SO_HIDE_RESTRICTCOLS); - } - - /* adds vertical offset */ - sizey += OL_Y_OFFSET; - - /* update size of tot-rect (extents of data/viewable area) */ - UI_view2d_totRect_set(v2d, sizex, sizey); - - /* force display to pixel coords */ - v2d->flag |= (V2D_PIXELOFS_X | V2D_PIXELOFS_Y); - /* set matrix for 2d-view controls */ - UI_view2d_view_ortho(v2d); - - /* draw outliner stuff (background, hierarchy lines and names) */ - outliner_back(ar); - block = UI_block_begin(C, ar, __func__, UI_EMBOSS); - outliner_draw_tree( - (bContext *)C, block, scene, view_layer, - ar, soops, has_restrict_icons, &te_edit); - - /* Default to no emboss for outliner UI. */ - UI_block_emboss_set(block, UI_EMBOSS_NONE); - - if (soops->outlinevis == SO_DATA_API) { - /* draw rna buttons */ - outliner_draw_rnacols(ar, sizex_rna); - - UI_block_emboss_set(block, UI_EMBOSS); - outliner_draw_rnabuts(block, ar, soops, sizex_rna, &soops->tree); - UI_block_emboss_set(block, UI_EMBOSS_NONE); - } - else if ((soops->outlinevis == SO_ID_ORPHANS) && has_restrict_icons) { - /* draw user toggle columns */ - outliner_draw_restrictcols(ar); - outliner_draw_userbuts(block, ar, soops, &soops->tree); - } - else if (has_restrict_icons) { - /* draw restriction columns */ - outliner_draw_restrictcols(ar); - - outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &soops->tree); - } - - UI_block_emboss_set(block, UI_EMBOSS); - - /* draw edit buttons if nessecery */ - if (te_edit) { - outliner_buttons(C, block, ar, te_edit); - } - - UI_block_end(C, block); - UI_block_draw(C, block); + Main *mainvar = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + ARegion *ar = CTX_wm_region(C); + View2D *v2d = &ar->v2d; + SpaceOutliner *soops = CTX_wm_space_outliner(C); + uiBlock *block; + int sizey = 0, sizex = 0, sizex_rna = 0; + TreeElement *te_edit = NULL; + bool has_restrict_icons; + + outliner_build_tree(mainvar, scene, view_layer, soops, ar); // always + + /* get extents of data */ + outliner_height(soops, &soops->tree, &sizey); + + /* extend size to allow for horizontal scrollbar */ + sizey += V2D_SCROLL_HEIGHT; + + if (soops->outlinevis == SO_DATA_API) { + /* RNA has two columns: + * - column 1 is (max_width + OL_RNA_COL_SPACEX) or + * (OL_RNA_COL_X), whichever is wider... + * - column 2 is fixed at OL_RNA_COL_SIZEX + * + * (*) XXX max width for now is a fixed factor of (UI_UNIT_X * (max_indention + 100)) + */ + + /* get actual width of column 1 */ + outliner_rna_width(soops, &soops->tree, &sizex_rna, 0); + sizex_rna = max_ii(OL_RNA_COLX, sizex_rna + OL_RNA_COL_SPACEX); + + /* get width of data (for setting 'tot' rect, this is column 1 + column 2 + a bit extra) */ + sizex = sizex_rna + OL_RNA_COL_SIZEX + 50; + has_restrict_icons = false; + } + else { + /* width must take into account restriction columns (if visible) + * so that entries will still be visible */ + //outliner_width(soops, &soops->tree, &sizex); + // XXX should use outliner_width instead when te->xend will be set correctly... + outliner_rna_width(soops, &soops->tree, &sizex, 0); + + /* constant offset for restriction columns */ + // XXX this isn't that great yet... + if ((soops->flag & SO_HIDE_RESTRICTCOLS) == 0) { + sizex += OL_TOGW * 3; + } + + has_restrict_icons = !(soops->flag & SO_HIDE_RESTRICTCOLS); + } + + /* adds vertical offset */ + sizey += OL_Y_OFFSET; + + /* update size of tot-rect (extents of data/viewable area) */ + UI_view2d_totRect_set(v2d, sizex, sizey); + + /* force display to pixel coords */ + v2d->flag |= (V2D_PIXELOFS_X | V2D_PIXELOFS_Y); + /* set matrix for 2d-view controls */ + UI_view2d_view_ortho(v2d); + + /* draw outliner stuff (background, hierarchy lines and names) */ + outliner_back(ar); + block = UI_block_begin(C, ar, __func__, UI_EMBOSS); + outliner_draw_tree( + (bContext *)C, block, scene, view_layer, ar, soops, has_restrict_icons, &te_edit); + + /* Default to no emboss for outliner UI. */ + UI_block_emboss_set(block, UI_EMBOSS_NONE); + + if (soops->outlinevis == SO_DATA_API) { + /* draw rna buttons */ + outliner_draw_rnacols(ar, sizex_rna); + + UI_block_emboss_set(block, UI_EMBOSS); + outliner_draw_rnabuts(block, ar, soops, sizex_rna, &soops->tree); + UI_block_emboss_set(block, UI_EMBOSS_NONE); + } + else if ((soops->outlinevis == SO_ID_ORPHANS) && has_restrict_icons) { + /* draw user toggle columns */ + outliner_draw_restrictcols(ar); + outliner_draw_userbuts(block, ar, soops, &soops->tree); + } + else if (has_restrict_icons) { + /* draw restriction columns */ + outliner_draw_restrictcols(ar); + + outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &soops->tree); + } + + UI_block_emboss_set(block, UI_EMBOSS); + + /* draw edit buttons if nessecery */ + if (te_edit) { + outliner_buttons(C, block, ar, te_edit); + } + + UI_block_end(C, block); + UI_block_draw(C, block); } diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 8b8dff9dc27..11d01931945 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -88,773 +88,840 @@ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { - /* Drag and drop does own highlighting. */ - wmWindowManager *wm = CTX_wm_manager(C); - if (wm->drags.first) { - return OPERATOR_PASS_THROUGH; - } + /* Drag and drop does own highlighting. */ + wmWindowManager *wm = CTX_wm_manager(C); + if (wm->drags.first) { + return OPERATOR_PASS_THROUGH; + } - ARegion *ar = CTX_wm_region(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]); + ARegion *ar = CTX_wm_region(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + const float my = UI_view2d_region_to_view_y(&ar->v2d, event->mval[1]); - TreeElement *hovered_te = outliner_find_item_at_y(soops, &soops->tree, my); - bool changed = false; + TreeElement *hovered_te = outliner_find_item_at_y(soops, &soops->tree, my); + bool changed = false; - if (!hovered_te || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED)) { - changed = outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false); - if (hovered_te) { - hovered_te->store_elem->flag |= TSE_HIGHLIGHTED; - changed = true; - } - } + if (!hovered_te || !(hovered_te->store_elem->flag & TSE_HIGHLIGHTED)) { + changed = outliner_flag_set(&soops->tree, TSE_HIGHLIGHTED | TSE_DRAG_ANY, false); + if (hovered_te) { + hovered_te->store_elem->flag |= TSE_HIGHLIGHTED; + changed = true; + } + } - if (changed) { - ED_region_tag_redraw_no_rebuild(ar); - } + if (changed) { + ED_region_tag_redraw_no_rebuild(ar); + } - return OPERATOR_PASS_THROUGH; + return OPERATOR_PASS_THROUGH; } void OUTLINER_OT_highlight_update(wmOperatorType *ot) { - ot->name = "Update Highlight"; - ot->idname = "OUTLINER_OT_highlight_update"; - ot->description = "Update the item highlight based on the current mouse position"; + ot->name = "Update Highlight"; + ot->idname = "OUTLINER_OT_highlight_update"; + ot->description = "Update the item highlight based on the current mouse position"; - ot->invoke = outliner_highlight_update; + ot->invoke = outliner_highlight_update; - ot->poll = ED_operator_outliner_active; + ot->poll = ED_operator_outliner_active; } /* Toggle Open/Closed ------------------------------------------- */ -static int do_outliner_item_openclose(bContext *C, SpaceOutliner *soops, TreeElement *te, const bool all, const float mval[2]) +static int do_outliner_item_openclose( + bContext *C, SpaceOutliner *soops, TreeElement *te, const bool all, const float mval[2]) { - if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { - TreeStoreElem *tselem = TREESTORE(te); + if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { + TreeStoreElem *tselem = TREESTORE(te); - /* all below close/open? */ - if (all) { - tselem->flag &= ~TSE_CLOSED; - outliner_flag_set(&te->subtree, TSE_CLOSED, !outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1)); - } - else { - if (tselem->flag & TSE_CLOSED) { - tselem->flag &= ~TSE_CLOSED; - } - else { - tselem->flag |= TSE_CLOSED; - } - } + /* all below close/open? */ + if (all) { + tselem->flag &= ~TSE_CLOSED; + outliner_flag_set( + &te->subtree, TSE_CLOSED, !outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1)); + } + else { + if (tselem->flag & TSE_CLOSED) { + tselem->flag &= ~TSE_CLOSED; + } + else { + tselem->flag |= TSE_CLOSED; + } + } - return 1; - } - - for (te = te->subtree.first; te; te = te->next) { - if (do_outliner_item_openclose(C, soops, te, all, mval)) { - return 1; - } - } - return 0; + return 1; + } + for (te = te->subtree.first; te; te = te->next) { + if (do_outliner_item_openclose(C, soops, te, all, mval)) { + return 1; + } + } + return 0; } /* event can enterkey, then it opens/closes */ static int outliner_item_openclose(bContext *C, wmOperator *op, const wmEvent *event) { - ARegion *ar = CTX_wm_region(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - TreeElement *te; - float fmval[2]; - const bool all = RNA_boolean_get(op->ptr, "all"); + ARegion *ar = CTX_wm_region(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + TreeElement *te; + float fmval[2]; + const bool all = RNA_boolean_get(op->ptr, "all"); - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - for (te = soops->tree.first; te; te = te->next) { - if (do_outliner_item_openclose(C, soops, te, all, fmval)) { - break; - } - } + for (te = soops->tree.first; te; te = te->next) { + if (do_outliner_item_openclose(C, soops, te, all, fmval)) { + break; + } + } - ED_region_tag_redraw(ar); + ED_region_tag_redraw(ar); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_item_openclose(wmOperatorType *ot) { - ot->name = "Open/Close"; - ot->idname = "OUTLINER_OT_item_openclose"; - ot->description = "Toggle whether item under cursor is enabled or closed"; + ot->name = "Open/Close"; + ot->idname = "OUTLINER_OT_item_openclose"; + ot->description = "Toggle whether item under cursor is enabled or closed"; - ot->invoke = outliner_item_openclose; + ot->invoke = outliner_item_openclose; - ot->poll = ED_operator_outliner_active; + ot->poll = ED_operator_outliner_active; - RNA_def_boolean(ot->srna, "all", 1, "All", "Close or open all items"); + RNA_def_boolean(ot->srna, "all", 1, "All", "Close or open all items"); } /* -------------------------------------------------------------------- */ /** \name Object Mode Enter/Exit * \{ */ -static void item_object_mode_enter_exit( - bContext *C, ReportList *reports, Object *ob, - bool enter) +static void item_object_mode_enter_exit(bContext *C, ReportList *reports, Object *ob, bool enter) { - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *obact = OBACT(view_layer); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *obact = OBACT(view_layer); - if ((ob->type != obact->type) || ID_IS_LINKED(ob->data)) { - return; - } - if (((ob->mode & obact->mode) != 0) == enter) { - return; - } + if ((ob->type != obact->type) || ID_IS_LINKED(ob->data)) { + return; + } + if (((ob->mode & obact->mode) != 0) == enter) { + return; + } - if (ob == obact) { - BKE_report(reports, RPT_WARNING, "Active object mode not changed"); - return; - } + if (ob == obact) { + BKE_report(reports, RPT_WARNING, "Active object mode not changed"); + return; + } - Base *base = BKE_view_layer_base_find(view_layer, ob); - if (base == NULL) { - return; - } - Scene *scene = CTX_data_scene(C); - outliner_object_mode_toggle(C, scene, view_layer, base); + Base *base = BKE_view_layer_base_find(view_layer, ob); + if (base == NULL) { + return; + } + Scene *scene = CTX_data_scene(C); + outliner_object_mode_toggle(C, scene, view_layer, base); } -void item_object_mode_enter_cb( - bContext *C, ReportList *reports, Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void item_object_mode_enter_cb(bContext *C, + ReportList *reports, + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) { - Object *ob = (Object *)tselem->id; - item_object_mode_enter_exit(C, reports, ob, true); + Object *ob = (Object *)tselem->id; + item_object_mode_enter_exit(C, reports, ob, true); } -void item_object_mode_exit_cb( - bContext *C, ReportList *reports, Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void item_object_mode_exit_cb(bContext *C, + ReportList *reports, + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) { - Object *ob = (Object *)tselem->id; - item_object_mode_enter_exit(C, reports, ob, false); + Object *ob = (Object *)tselem->id; + item_object_mode_enter_exit(C, reports, ob, false); } /** \} */ /* Rename --------------------------------------------------- */ -static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, +static void do_item_rename(ARegion *ar, + TreeElement *te, + TreeStoreElem *tselem, ReportList *reports) { - bool add_textbut = false; - - /* can't rename rna datablocks entries or listbases */ - if (ELEM(tselem->type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE, TSE_SCENE_OBJECTS_BASE)) { - /* do nothing */ - } - else if (ELEM(tselem->type, TSE_ANIM_DATA, TSE_NLA, TSE_DEFGROUP_BASE, TSE_CONSTRAINT_BASE, TSE_MODIFIER_BASE, - TSE_DRIVER_BASE, TSE_POSE_BASE, TSE_POSEGRP_BASE, TSE_R_LAYER_BASE, TSE_SCENE_COLLECTION_BASE, - TSE_VIEW_COLLECTION_BASE)) - { - BKE_report(reports, RPT_WARNING, "Cannot edit builtin name"); - } - else if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { - BKE_report(reports, RPT_WARNING, "Cannot edit sequence name"); - } - else if (outliner_is_collection_tree_element(te)) { - Collection *collection = outliner_collection_from_tree_element(te); - - if (collection->flag & COLLECTION_IS_MASTER) { - BKE_report(reports, RPT_WARNING, "Cannot edit name of master collection"); - } - else { - add_textbut = true; - } - } - else if (ID_IS_LINKED(tselem->id)) { - BKE_report(reports, RPT_WARNING, "Cannot edit external library data"); - } - else if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) { - BKE_report(reports, RPT_WARNING, "Cannot edit the path of an indirectly linked library"); - } - else { - add_textbut = true; - } - - if (add_textbut) { - tselem->flag |= TSE_TEXTBUT; - ED_region_tag_redraw(ar); - } -} - -void item_rename_cb( - bContext *C, ReportList *reports, Scene *UNUSED(scene), TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - ARegion *ar = CTX_wm_region(C); - do_item_rename(ar, te, tselem, reports); -} - -static int do_outliner_item_rename(ReportList *reports, ARegion *ar, TreeElement *te, + bool add_textbut = false; + + /* can't rename rna datablocks entries or listbases */ + if (ELEM(tselem->type, + TSE_RNA_STRUCT, + TSE_RNA_PROPERTY, + TSE_RNA_ARRAY_ELEM, + TSE_ID_BASE, + TSE_SCENE_OBJECTS_BASE)) { + /* do nothing */ + } + else if (ELEM(tselem->type, + TSE_ANIM_DATA, + TSE_NLA, + TSE_DEFGROUP_BASE, + TSE_CONSTRAINT_BASE, + TSE_MODIFIER_BASE, + TSE_DRIVER_BASE, + TSE_POSE_BASE, + TSE_POSEGRP_BASE, + TSE_R_LAYER_BASE, + TSE_SCENE_COLLECTION_BASE, + TSE_VIEW_COLLECTION_BASE)) { + BKE_report(reports, RPT_WARNING, "Cannot edit builtin name"); + } + else if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { + BKE_report(reports, RPT_WARNING, "Cannot edit sequence name"); + } + else if (outliner_is_collection_tree_element(te)) { + Collection *collection = outliner_collection_from_tree_element(te); + + if (collection->flag & COLLECTION_IS_MASTER) { + BKE_report(reports, RPT_WARNING, "Cannot edit name of master collection"); + } + else { + add_textbut = true; + } + } + else if (ID_IS_LINKED(tselem->id)) { + BKE_report(reports, RPT_WARNING, "Cannot edit external library data"); + } + else if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) { + BKE_report(reports, RPT_WARNING, "Cannot edit the path of an indirectly linked library"); + } + else { + add_textbut = true; + } + + if (add_textbut) { + tselem->flag |= TSE_TEXTBUT; + ED_region_tag_redraw(ar); + } +} + +void item_rename_cb(bContext *C, + ReportList *reports, + Scene *UNUSED(scene), + TreeElement *te, + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) +{ + ARegion *ar = CTX_wm_region(C); + do_item_rename(ar, te, tselem, reports); +} + +static int do_outliner_item_rename(ReportList *reports, + ARegion *ar, + TreeElement *te, const float mval[2]) { - if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { - TreeStoreElem *tselem = TREESTORE(te); + if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { + TreeStoreElem *tselem = TREESTORE(te); - /* click on name */ - if (mval[0] > te->xs + UI_UNIT_X * 2 && mval[0] < te->xend) { - do_item_rename(ar, te, tselem, reports); - return 1; - } - return 0; - } + /* click on name */ + if (mval[0] > te->xs + UI_UNIT_X * 2 && mval[0] < te->xend) { + do_item_rename(ar, te, tselem, reports); + return 1; + } + return 0; + } - for (te = te->subtree.first; te; te = te->next) { - if (do_outliner_item_rename(reports, ar, te, mval)) { - return 1; - } - } - return 0; + for (te = te->subtree.first; te; te = te->next) { + if (do_outliner_item_rename(reports, ar, te, mval)) { + return 1; + } + } + return 0; } static int outliner_item_rename(bContext *C, wmOperator *op, const wmEvent *event) { - ARegion *ar = CTX_wm_region(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - TreeElement *te; - float fmval[2]; - bool changed = false; + ARegion *ar = CTX_wm_region(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + TreeElement *te; + float fmval[2]; + bool changed = false; - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - for (te = soops->tree.first; te; te = te->next) { - if (do_outliner_item_rename(op->reports, ar, te, fmval)) { - changed = true; - break; - } - } + for (te = soops->tree.first; te; te = te->next) { + if (do_outliner_item_rename(op->reports, ar, te, fmval)) { + changed = true; + break; + } + } - return changed ? OPERATOR_FINISHED : OPERATOR_PASS_THROUGH; + return changed ? OPERATOR_FINISHED : OPERATOR_PASS_THROUGH; } - void OUTLINER_OT_item_rename(wmOperatorType *ot) { - ot->name = "Rename"; - ot->idname = "OUTLINER_OT_item_rename"; - ot->description = "Rename item under cursor"; + ot->name = "Rename"; + ot->idname = "OUTLINER_OT_item_rename"; + ot->description = "Rename item under cursor"; - ot->invoke = outliner_item_rename; + ot->invoke = outliner_item_rename; - ot->poll = ED_operator_outliner_active; + ot->poll = ED_operator_outliner_active; } /* ID delete --------------------------------------------------- */ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem) { - Main *bmain = CTX_data_main(C); - ID *id = tselem->id; - - BLI_assert(te->idcode != 0 && id != NULL); - UNUSED_VARS_NDEBUG(te); - - if (te->idcode == ID_LI && ((Library *)id)->parent != NULL) { - BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked library '%s'", id->name); - return; - } - if (id->tag & LIB_TAG_INDIRECT) { - BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked id '%s'", id->name); - return; - } - else if (BKE_library_ID_is_indirectly_used(bmain, id) && ID_REAL_USERS(id) <= 1) { - BKE_reportf(reports, RPT_WARNING, - "Cannot delete id '%s', indirectly used data-blocks need at least one user", - id->name); - return; - } - - - BKE_id_delete(bmain, id); - - WM_event_add_notifier(C, NC_WINDOW, NULL); -} - -void id_delete_cb( - bContext *C, ReportList *reports, Scene *UNUSED(scene), - TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - id_delete(C, reports, te, tselem); -} - -static int outliner_id_delete_invoke_do(bContext *C, ReportList *reports, TreeElement *te, const float mval[2]) -{ - if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { - TreeStoreElem *tselem = TREESTORE(te); - - if (te->idcode != 0 && tselem->id) { - if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) { - BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, - "Cannot delete indirectly linked library '%s'", ((Library *)tselem->id)->filepath); - return OPERATOR_CANCELLED; - } - id_delete(C, reports, te, tselem); - return OPERATOR_FINISHED; - } - } - else { - for (te = te->subtree.first; te; te = te->next) { - int ret; - if ((ret = outliner_id_delete_invoke_do(C, reports, te, mval))) { - return ret; - } - } - } - - return 0; + Main *bmain = CTX_data_main(C); + ID *id = tselem->id; + + BLI_assert(te->idcode != 0 && id != NULL); + UNUSED_VARS_NDEBUG(te); + + if (te->idcode == ID_LI && ((Library *)id)->parent != NULL) { + BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked library '%s'", id->name); + return; + } + if (id->tag & LIB_TAG_INDIRECT) { + BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked id '%s'", id->name); + return; + } + else if (BKE_library_ID_is_indirectly_used(bmain, id) && ID_REAL_USERS(id) <= 1) { + BKE_reportf(reports, + RPT_WARNING, + "Cannot delete id '%s', indirectly used data-blocks need at least one user", + id->name); + return; + } + + BKE_id_delete(bmain, id); + + WM_event_add_notifier(C, NC_WINDOW, NULL); +} + +void id_delete_cb(bContext *C, + ReportList *reports, + Scene *UNUSED(scene), + TreeElement *te, + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) +{ + id_delete(C, reports, te, tselem); +} + +static int outliner_id_delete_invoke_do(bContext *C, + ReportList *reports, + TreeElement *te, + const float mval[2]) +{ + if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { + TreeStoreElem *tselem = TREESTORE(te); + + if (te->idcode != 0 && tselem->id) { + if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) { + BKE_reportf(reports, + RPT_ERROR_INVALID_INPUT, + "Cannot delete indirectly linked library '%s'", + ((Library *)tselem->id)->filepath); + return OPERATOR_CANCELLED; + } + id_delete(C, reports, te, tselem); + return OPERATOR_FINISHED; + } + } + else { + for (te = te->subtree.first; te; te = te->next) { + int ret; + if ((ret = outliner_id_delete_invoke_do(C, reports, te, mval))) { + return ret; + } + } + } + + return 0; } static int outliner_id_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - ARegion *ar = CTX_wm_region(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - TreeElement *te; - float fmval[2]; + ARegion *ar = CTX_wm_region(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + TreeElement *te; + float fmval[2]; - BLI_assert(ar && soops); + BLI_assert(ar && soops); - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - for (te = soops->tree.first; te; te = te->next) { - int ret; + for (te = soops->tree.first; te; te = te->next) { + int ret; - if ((ret = outliner_id_delete_invoke_do(C, op->reports, te, fmval))) { - return ret; - } - } + if ((ret = outliner_id_delete_invoke_do(C, op->reports, te, fmval))) { + return ret; + } + } - return OPERATOR_CANCELLED; + return OPERATOR_CANCELLED; } void OUTLINER_OT_id_delete(wmOperatorType *ot) { - ot->name = "Delete Data-Block"; - ot->idname = "OUTLINER_OT_id_delete"; - ot->description = "Delete the ID under cursor"; + ot->name = "Delete Data-Block"; + ot->idname = "OUTLINER_OT_id_delete"; + ot->description = "Delete the ID under cursor"; - ot->invoke = outliner_id_delete_invoke; - ot->poll = ED_operator_outliner_active; + ot->invoke = outliner_id_delete_invoke; + ot->poll = ED_operator_outliner_active; } /* ID remap --------------------------------------------------- */ static int outliner_id_remap_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); + Main *bmain = CTX_data_main(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); - const short id_type = (short)RNA_enum_get(op->ptr, "id_type"); - ID *old_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id")); - ID *new_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id")); + const short id_type = (short)RNA_enum_get(op->ptr, "id_type"); + ID *old_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), + RNA_enum_get(op->ptr, "old_id")); + ID *new_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), + RNA_enum_get(op->ptr, "new_id")); - /* check for invalid states */ - if (soops == NULL) { - return OPERATOR_CANCELLED; - } + /* check for invalid states */ + if (soops == NULL) { + return OPERATOR_CANCELLED; + } - if (!(old_id && new_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) { - BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, "Invalid old/new ID pair ('%s' / '%s')", - old_id ? old_id->name : "Invalid ID", new_id ? new_id->name : "Invalid ID"); - return OPERATOR_CANCELLED; - } + if (!(old_id && new_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) { + BKE_reportf(op->reports, + RPT_ERROR_INVALID_INPUT, + "Invalid old/new ID pair ('%s' / '%s')", + old_id ? old_id->name : "Invalid ID", + new_id ? new_id->name : "Invalid ID"); + return OPERATOR_CANCELLED; + } - if (ID_IS_LINKED(old_id)) { - BKE_reportf(op->reports, RPT_WARNING, - "Old ID '%s' is linked from a library, indirect usages of this data-block will not be remapped", - old_id->name); - } + if (ID_IS_LINKED(old_id)) { + BKE_reportf(op->reports, + RPT_WARNING, + "Old ID '%s' is linked from a library, indirect usages of this data-block will " + "not be remapped", + old_id->name); + } - BKE_libblock_remap(bmain, old_id, new_id, - ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE); + BKE_libblock_remap( + bmain, old_id, new_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE); - BKE_main_lib_objects_recalc_all(bmain); + BKE_main_lib_objects_recalc_all(bmain); - /* recreate dependency graph to include new objects */ - DEG_relations_tag_update(bmain); + /* recreate dependency graph to include new objects */ + DEG_relations_tag_update(bmain); - /* Free gpu materials, some materials depend on existing objects, - * such as lights so freeing correctly refreshes. */ - GPU_materials_free(bmain); + /* Free gpu materials, some materials depend on existing objects, + * such as lights so freeing correctly refreshes. */ + GPU_materials_free(bmain); - WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_WINDOW, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } -static bool outliner_id_remap_find_tree_element(bContext *C, wmOperator *op, ListBase *tree, const float y) +static bool outliner_id_remap_find_tree_element(bContext *C, + wmOperator *op, + ListBase *tree, + const float y) { - TreeElement *te; + TreeElement *te; - for (te = tree->first; te; te = te->next) { - if (y > te->ys && y < te->ys + UI_UNIT_Y) { - TreeStoreElem *tselem = TREESTORE(te); + for (te = tree->first; te; te = te->next) { + if (y > te->ys && y < te->ys + UI_UNIT_Y) { + TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && tselem->id) { - printf("found id %s (%p)!\n", tselem->id->name, tselem->id); + if (tselem->type == 0 && tselem->id) { + printf("found id %s (%p)!\n", tselem->id->name, tselem->id); - RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name)); - RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2); - RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2); - return true; - } - } - if (outliner_id_remap_find_tree_element(C, op, &te->subtree, y)) { - return true; - } - } - return false; + RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name)); + RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2); + RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2); + return true; + } + } + if (outliner_id_remap_find_tree_element(C, op, &te->subtree, y)) { + return true; + } + } + return false; } static int outliner_id_remap_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - ARegion *ar = CTX_wm_region(C); - float fmval[2]; + SpaceOutliner *soops = CTX_wm_space_outliner(C); + ARegion *ar = CTX_wm_region(C); + float fmval[2]; - if (!RNA_property_is_set(op->ptr, RNA_struct_find_property(op->ptr, "id_type"))) { - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + if (!RNA_property_is_set(op->ptr, RNA_struct_find_property(op->ptr, "id_type"))) { + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - outliner_id_remap_find_tree_element(C, op, &soops->tree, fmval[1]); - } + outliner_id_remap_find_tree_element(C, op, &soops->tree, fmval[1]); + } - return WM_operator_props_dialog_popup(C, op, 200, 100); + return WM_operator_props_dialog_popup(C, op, 200, 100); } -static const EnumPropertyItem *outliner_id_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) +static const EnumPropertyItem *outliner_id_itemf(bContext *C, + PointerRNA *ptr, + PropertyRNA *UNUSED(prop), + bool *r_free) { - EnumPropertyItem item_tmp = {0}, *item = NULL; - int totitem = 0; - int i = 0; + EnumPropertyItem item_tmp = {0}, *item = NULL; + int totitem = 0; + int i = 0; - short id_type = (short)RNA_enum_get(ptr, "id_type"); - ID *id = which_libbase(CTX_data_main(C), id_type)->first; + short id_type = (short)RNA_enum_get(ptr, "id_type"); + ID *id = which_libbase(CTX_data_main(C), id_type)->first; - for (; id; id = id->next) { - item_tmp.identifier = item_tmp.name = id->name + 2; - item_tmp.value = i++; - RNA_enum_item_add(&item, &totitem, &item_tmp); - } + for (; id; id = id->next) { + item_tmp.identifier = item_tmp.name = id->name + 2; + item_tmp.value = i++; + RNA_enum_item_add(&item, &totitem, &item_tmp); + } - RNA_enum_item_end(&item, &totitem); - *r_free = true; + RNA_enum_item_end(&item, &totitem); + *r_free = true; - return item; + return item; } void OUTLINER_OT_id_remap(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Outliner ID data Remap"; - ot->idname = "OUTLINER_OT_id_remap"; + /* identifiers */ + ot->name = "Outliner ID data Remap"; + ot->idname = "OUTLINER_OT_id_remap"; - /* callbacks */ - ot->invoke = outliner_id_remap_invoke; - ot->exec = outliner_id_remap_exec; - ot->poll = ED_operator_outliner_active; + /* callbacks */ + ot->invoke = outliner_id_remap_invoke; + ot->exec = outliner_id_remap_exec; + ot->poll = ED_operator_outliner_active; - ot->flag = 0; + ot->flag = 0; - prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", ""); - RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID); + prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", ""); + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID); - prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace"); - RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, outliner_id_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN); + prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, outliner_id_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN); - ot->prop = RNA_def_enum(ot->srna, "new_id", DummyRNA_NULL_items, 0, - "New ID", "New ID to remap all selected IDs' users to"); - RNA_def_property_enum_funcs_runtime(ot->prop, NULL, NULL, outliner_id_itemf); - RNA_def_property_flag(ot->prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = RNA_def_enum(ot->srna, + "new_id", + DummyRNA_NULL_items, + 0, + "New ID", + "New ID to remap all selected IDs' users to"); + RNA_def_property_enum_funcs_runtime(ot->prop, NULL, NULL, outliner_id_itemf); + RNA_def_property_flag(ot->prop, PROP_ENUM_NO_TRANSLATE); } -void id_remap_cb( - bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void id_remap_cb(bContext *C, + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) { - wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false); - PointerRNA op_props; + wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false); + PointerRNA op_props; - BLI_assert(tselem->id != NULL); + BLI_assert(tselem->id != NULL); - WM_operator_properties_create_ptr(&op_props, ot); + WM_operator_properties_create_ptr(&op_props, ot); - RNA_enum_set(&op_props, "id_type", GS(tselem->id->name)); - RNA_enum_set_identifier(C, &op_props, "old_id", tselem->id->name + 2); + RNA_enum_set(&op_props, "id_type", GS(tselem->id->name)); + RNA_enum_set_identifier(C, &op_props, "old_id", tselem->id->name + 2); - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props); - WM_operator_properties_free(&op_props); + WM_operator_properties_free(&op_props); } /* ID copy/Paste ------------------------------------------------------------- */ static int outliner_id_copy_tag(SpaceOutliner *soops, ListBase *tree) { - TreeElement *te; - TreeStoreElem *tselem; - int num_ids = 0; + TreeElement *te; + TreeStoreElem *tselem; + int num_ids = 0; - for (te = tree->first; te; te = te->next) { - tselem = TREESTORE(te); + for (te = tree->first; te; te = te->next) { + tselem = TREESTORE(te); - /* if item is selected and is an ID, tag it as needing to be copied. */ - if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { - ID *id = tselem->id; - if (!(id->tag & LIB_TAG_DOIT)) { - BKE_copybuffer_tag_ID(tselem->id); - num_ids++; - } - } + /* if item is selected and is an ID, tag it as needing to be copied. */ + if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { + ID *id = tselem->id; + if (!(id->tag & LIB_TAG_DOIT)) { + BKE_copybuffer_tag_ID(tselem->id); + num_ids++; + } + } - /* go over sub-tree */ - if (TSELEM_OPEN(tselem, soops)) { - num_ids += outliner_id_copy_tag(soops, &te->subtree); - } - } + /* go over sub-tree */ + if (TSELEM_OPEN(tselem, soops)) { + num_ids += outliner_id_copy_tag(soops, &te->subtree); + } + } - return num_ids; + return num_ids; } static int outliner_id_copy_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - char str[FILE_MAX]; + Main *bmain = CTX_data_main(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + char str[FILE_MAX]; - BKE_copybuffer_begin(bmain); + BKE_copybuffer_begin(bmain); - const int num_ids = outliner_id_copy_tag(soops, &soops->tree); - if (num_ids == 0) { - BKE_report(op->reports, RPT_INFO, "No selected data-blocks to copy"); - return OPERATOR_CANCELLED; - } + const int num_ids = outliner_id_copy_tag(soops, &soops->tree); + if (num_ids == 0) { + BKE_report(op->reports, RPT_INFO, "No selected data-blocks to copy"); + return OPERATOR_CANCELLED; + } - BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend"); - BKE_copybuffer_save(bmain, str, op->reports); + BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend"); + BKE_copybuffer_save(bmain, str, op->reports); - BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-blocks", num_ids); + BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-blocks", num_ids); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_id_copy(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Outliner ID Data Copy"; - ot->idname = "OUTLINER_OT_id_copy"; - ot->description = "Selected data-blocks are copied to the clipboard"; + /* identifiers */ + ot->name = "Outliner ID Data Copy"; + ot->idname = "OUTLINER_OT_id_copy"; + ot->description = "Selected data-blocks are copied to the clipboard"; - /* callbacks */ - ot->exec = outliner_id_copy_exec; - ot->poll = ED_operator_outliner_active; + /* callbacks */ + ot->exec = outliner_id_copy_exec; + ot->poll = ED_operator_outliner_active; - ot->flag = 0; + ot->flag = 0; } static int outliner_id_paste_exec(bContext *C, wmOperator *op) { - char str[FILE_MAX]; - const short flag = FILE_AUTOSELECT | FILE_ACTIVE_COLLECTION; + char str[FILE_MAX]; + const short flag = FILE_AUTOSELECT | FILE_ACTIVE_COLLECTION; - BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend"); + BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend"); - const int num_pasted = BKE_copybuffer_paste(C, str, flag, op->reports, 0); - if (num_pasted == 0) { - BKE_report(op->reports, RPT_INFO, "No data to paste"); - return OPERATOR_CANCELLED; - } + const int num_pasted = BKE_copybuffer_paste(C, str, flag, op->reports, 0); + if (num_pasted == 0) { + BKE_report(op->reports, RPT_INFO, "No data to paste"); + return OPERATOR_CANCELLED; + } - WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_WINDOW, NULL); - BKE_reportf(op->reports, RPT_INFO, "%d data-blocks pasted", num_pasted); - return OPERATOR_FINISHED; + BKE_reportf(op->reports, RPT_INFO, "%d data-blocks pasted", num_pasted); + return OPERATOR_FINISHED; } void OUTLINER_OT_id_paste(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Outliner ID Data Paste"; - ot->idname = "OUTLINER_OT_id_paste"; - ot->description = "Data-blocks from the clipboard are pasted"; + /* identifiers */ + ot->name = "Outliner ID Data Paste"; + ot->idname = "OUTLINER_OT_id_paste"; + ot->description = "Data-blocks from the clipboard are pasted"; - /* callbacks */ - ot->exec = outliner_id_paste_exec; - ot->poll = ED_operator_outliner_active; + /* callbacks */ + ot->exec = outliner_id_paste_exec; + ot->poll = ED_operator_outliner_active; - ot->flag = 0; + ot->flag = 0; } /* Library relocate/reload --------------------------------------------------- */ static int lib_relocate( - bContext *C, TreeElement *te, TreeStoreElem *tselem, wmOperatorType *ot, const bool reload) + bContext *C, TreeElement *te, TreeStoreElem *tselem, wmOperatorType *ot, const bool reload) { - PointerRNA op_props; - int ret = 0; + PointerRNA op_props; + int ret = 0; - BLI_assert(te->idcode == ID_LI && tselem->id != NULL); - UNUSED_VARS_NDEBUG(te); + BLI_assert(te->idcode == ID_LI && tselem->id != NULL); + UNUSED_VARS_NDEBUG(te); - WM_operator_properties_create_ptr(&op_props, ot); + WM_operator_properties_create_ptr(&op_props, ot); - RNA_string_set(&op_props, "library", tselem->id->name + 2); + RNA_string_set(&op_props, "library", tselem->id->name + 2); - if (reload) { - Library *lib = (Library *)tselem->id; - char dir[FILE_MAXDIR], filename[FILE_MAX]; + if (reload) { + Library *lib = (Library *)tselem->id; + char dir[FILE_MAXDIR], filename[FILE_MAX]; - BLI_split_dirfile(lib->filepath, dir, filename, sizeof(dir), sizeof(filename)); + BLI_split_dirfile(lib->filepath, dir, filename, sizeof(dir), sizeof(filename)); - printf("%s, %s\n", tselem->id->name, lib->filepath); + printf("%s, %s\n", tselem->id->name, lib->filepath); - /* We assume if both paths in lib are not the same then lib->name was relative... */ - RNA_boolean_set(&op_props, "relative_path", BLI_path_cmp(lib->filepath, lib->name) != 0); + /* We assume if both paths in lib are not the same then lib->name was relative... */ + RNA_boolean_set(&op_props, "relative_path", BLI_path_cmp(lib->filepath, lib->name) != 0); - RNA_string_set(&op_props, "directory", dir); - RNA_string_set(&op_props, "filename", filename); + RNA_string_set(&op_props, "directory", dir); + RNA_string_set(&op_props, "filename", filename); - ret = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props); - } - else { - ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props); - } + ret = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props); + } + else { + ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props); + } - WM_operator_properties_free(&op_props); + WM_operator_properties_free(&op_props); - return ret; + return ret; } static int outliner_lib_relocate_invoke_do( - bContext *C, ReportList *reports, TreeElement *te, const float mval[2], const bool reload) -{ - if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { - TreeStoreElem *tselem = TREESTORE(te); - - if (te->idcode == ID_LI && tselem->id) { - if (((Library *)tselem->id)->parent && !reload) { - BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, - "Cannot relocate indirectly linked library '%s'", ((Library *)tselem->id)->filepath); - return OPERATOR_CANCELLED; - } - else { - wmOperatorType *ot = WM_operatortype_find(reload ? "WM_OT_lib_reload" : "WM_OT_lib_relocate", false); - - return lib_relocate(C, te, tselem, ot, reload); - } - } - } - else { - for (te = te->subtree.first; te; te = te->next) { - int ret; - if ((ret = outliner_lib_relocate_invoke_do(C, reports, te, mval, reload))) { - return ret; - } - } - } - - return 0; + bContext *C, ReportList *reports, TreeElement *te, const float mval[2], const bool reload) +{ + if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { + TreeStoreElem *tselem = TREESTORE(te); + + if (te->idcode == ID_LI && tselem->id) { + if (((Library *)tselem->id)->parent && !reload) { + BKE_reportf(reports, + RPT_ERROR_INVALID_INPUT, + "Cannot relocate indirectly linked library '%s'", + ((Library *)tselem->id)->filepath); + return OPERATOR_CANCELLED; + } + else { + wmOperatorType *ot = WM_operatortype_find( + reload ? "WM_OT_lib_reload" : "WM_OT_lib_relocate", false); + + return lib_relocate(C, te, tselem, ot, reload); + } + } + } + else { + for (te = te->subtree.first; te; te = te->next) { + int ret; + if ((ret = outliner_lib_relocate_invoke_do(C, reports, te, mval, reload))) { + return ret; + } + } + } + + return 0; } static int outliner_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - ARegion *ar = CTX_wm_region(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - TreeElement *te; - float fmval[2]; + ARegion *ar = CTX_wm_region(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + TreeElement *te; + float fmval[2]; - BLI_assert(ar && soops); + BLI_assert(ar && soops); - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - for (te = soops->tree.first; te; te = te->next) { - int ret; + for (te = soops->tree.first; te; te = te->next) { + int ret; - if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, false))) { - return ret; - } - } + if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, false))) { + return ret; + } + } - return OPERATOR_CANCELLED; + return OPERATOR_CANCELLED; } void OUTLINER_OT_lib_relocate(wmOperatorType *ot) { - ot->name = "Relocate Library"; - ot->idname = "OUTLINER_OT_lib_relocate"; - ot->description = "Relocate the library under cursor"; + ot->name = "Relocate Library"; + ot->idname = "OUTLINER_OT_lib_relocate"; + ot->description = "Relocate the library under cursor"; - ot->invoke = outliner_lib_relocate_invoke; - ot->poll = ED_operator_outliner_active; + ot->invoke = outliner_lib_relocate_invoke; + ot->poll = ED_operator_outliner_active; } /* XXX This does not work with several items * (it is only called once in the end, due to the 'deferred' * filebrowser invocation through event system...). */ -void lib_relocate_cb( - bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void lib_relocate_cb(bContext *C, + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *te, + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) { - wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_relocate", false); + wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_relocate", false); - lib_relocate(C, te, tselem, ot, false); + lib_relocate(C, te, tselem, ot, false); } - static int outliner_lib_reload_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - ARegion *ar = CTX_wm_region(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - TreeElement *te; - float fmval[2]; + ARegion *ar = CTX_wm_region(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + TreeElement *te; + float fmval[2]; - BLI_assert(ar && soops); + BLI_assert(ar && soops); - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - for (te = soops->tree.first; te; te = te->next) { - int ret; + for (te = soops->tree.first; te; te = te->next) { + int ret; - if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, true))) { - return ret; - } - } + if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, true))) { + return ret; + } + } - return OPERATOR_CANCELLED; + return OPERATOR_CANCELLED; } void OUTLINER_OT_lib_reload(wmOperatorType *ot) { - ot->name = "Reload Library"; - ot->idname = "OUTLINER_OT_lib_reload"; - ot->description = "Reload the library under cursor"; + ot->name = "Reload Library"; + ot->idname = "OUTLINER_OT_lib_reload"; + ot->description = "Reload the library under cursor"; - ot->invoke = outliner_lib_reload_invoke; - ot->poll = ED_operator_outliner_active; + ot->invoke = outliner_lib_reload_invoke; + ot->poll = ED_operator_outliner_active; } -void lib_reload_cb( - bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void lib_reload_cb(bContext *C, + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *te, + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) { - wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_reload", false); + wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_reload", false); - lib_relocate(C, te, tselem, ot, true); + lib_relocate(C, te, tselem, ot, true); } /* ************************************************************** */ @@ -867,37 +934,37 @@ void lib_reload_cb( static int outliner_count_levels(ListBase *lb, const int curlevel) { - TreeElement *te; - int level = curlevel, lev; + TreeElement *te; + int level = curlevel, lev; - for (te = lb->first; te; te = te->next) { + for (te = lb->first; te; te = te->next) { - lev = outliner_count_levels(&te->subtree, curlevel + 1); - if (lev > level) { - level = lev; - } - } - return level; + lev = outliner_count_levels(&te->subtree, curlevel + 1); + if (lev > level) { + level = lev; + } + } + return level; } int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel) { - TreeElement *te; - TreeStoreElem *tselem; - int level; + TreeElement *te; + TreeStoreElem *tselem; + int level; - for (te = lb->first; te; te = te->next) { - tselem = TREESTORE(te); - if (tselem->flag & flag) { - return curlevel; - } + for (te = lb->first; te; te = te->next) { + tselem = TREESTORE(te); + if (tselem->flag & flag) { + return curlevel; + } - level = outliner_flag_is_any_test(&te->subtree, flag, curlevel + 1); - if (level) { - return level; - } - } - return 0; + level = outliner_flag_is_any_test(&te->subtree, flag, curlevel + 1); + if (level) { + return level; + } + } + return 0; } /** @@ -906,43 +973,43 @@ int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel) */ bool outliner_flag_set(ListBase *lb, short flag, short set) { - TreeElement *te; - TreeStoreElem *tselem; - bool changed = false; - bool has_flag; - - for (te = lb->first; te; te = te->next) { - tselem = TREESTORE(te); - has_flag = (tselem->flag & flag); - if (set == 0) { - if (has_flag) { - tselem->flag &= ~flag; - changed = true; - } - } - else if (!has_flag) { - tselem->flag |= flag; - changed = true; - } - changed |= outliner_flag_set(&te->subtree, flag, set); - } - - return changed; + TreeElement *te; + TreeStoreElem *tselem; + bool changed = false; + bool has_flag; + + for (te = lb->first; te; te = te->next) { + tselem = TREESTORE(te); + has_flag = (tselem->flag & flag); + if (set == 0) { + if (has_flag) { + tselem->flag &= ~flag; + changed = true; + } + } + else if (!has_flag) { + tselem->flag |= flag; + changed = true; + } + changed |= outliner_flag_set(&te->subtree, flag, set); + } + + return changed; } bool outliner_flag_flip(ListBase *lb, short flag) { - TreeElement *te; - TreeStoreElem *tselem; - bool changed = false; + TreeElement *te; + TreeStoreElem *tselem; + bool changed = false; - for (te = lb->first; te; te = te->next) { - tselem = TREESTORE(te); - tselem->flag ^= flag; - changed |= outliner_flag_flip(&te->subtree, flag); - } + for (te = lb->first; te; te = te->next) { + tselem = TREESTORE(te); + tselem->flag ^= flag; + changed |= outliner_flag_flip(&te->subtree, flag); + } - return changed; + return changed; } /* Restriction Columns ------------------------------- */ @@ -952,23 +1019,23 @@ bool outliner_flag_flip(ListBase *lb, short flag) * otherwise return 1 */ int common_restrict_check(bContext *C, Object *ob) { - /* Don't allow hide an object in edit mode, - * check the bug #22153 and #21609, #23977 - */ - Object *obedit = CTX_data_edit_object(C); - if (obedit && obedit == ob) { - /* found object is hidden, reset */ - if (ob->restrictflag & OB_RESTRICT_VIEW) { - ob->restrictflag &= ~OB_RESTRICT_VIEW; - } - /* found object is unselectable, reset */ - if (ob->restrictflag & OB_RESTRICT_SELECT) { - ob->restrictflag &= ~OB_RESTRICT_SELECT; - } - return 0; - } - - return 1; + /* Don't allow hide an object in edit mode, + * check the bug #22153 and #21609, #23977 + */ + Object *obedit = CTX_data_edit_object(C); + if (obedit && obedit == ob) { + /* found object is hidden, reset */ + if (ob->restrictflag & OB_RESTRICT_VIEW) { + ob->restrictflag &= ~OB_RESTRICT_VIEW; + } + /* found object is unselectable, reset */ + if (ob->restrictflag & OB_RESTRICT_SELECT) { + ob->restrictflag &= ~OB_RESTRICT_SELECT; + } + return 0; + } + + return 1; } /* =============================================== */ @@ -978,81 +1045,81 @@ int common_restrict_check(bContext *C, Object *ob) static int outliner_toggle_expanded_exec(bContext *C, wmOperator *UNUSED(op)) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - ARegion *ar = CTX_wm_region(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + ARegion *ar = CTX_wm_region(C); - if (outliner_flag_is_any_test(&soops->tree, TSE_CLOSED, 1)) { - outliner_flag_set(&soops->tree, TSE_CLOSED, 0); - } - else { - outliner_flag_set(&soops->tree, TSE_CLOSED, 1); - } + if (outliner_flag_is_any_test(&soops->tree, TSE_CLOSED, 1)) { + outliner_flag_set(&soops->tree, TSE_CLOSED, 0); + } + else { + outliner_flag_set(&soops->tree, TSE_CLOSED, 1); + } - ED_region_tag_redraw(ar); + ED_region_tag_redraw(ar); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_expanded_toggle(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Expand/Collapse All"; - ot->idname = "OUTLINER_OT_expanded_toggle"; - ot->description = "Expand/Collapse all items"; + /* identifiers */ + ot->name = "Expand/Collapse All"; + ot->idname = "OUTLINER_OT_expanded_toggle"; + ot->description = "Expand/Collapse all items"; - /* callbacks */ - ot->exec = outliner_toggle_expanded_exec; - ot->poll = ED_operator_outliner_active; + /* callbacks */ + ot->exec = outliner_toggle_expanded_exec; + ot->poll = ED_operator_outliner_active; - /* no undo or registry, UI option */ + /* no undo or registry, UI option */ } /* Toggle Selected (Outliner) ---------------------------------------- */ static int outliner_select_all_exec(bContext *C, wmOperator *op) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - ARegion *ar = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); - int action = RNA_enum_get(op->ptr, "action"); - if (action == SEL_TOGGLE) { - action = outliner_flag_is_any_test(&soops->tree, TSE_SELECTED, 1) ? SEL_DESELECT : SEL_SELECT; - } - - switch (action) { - case SEL_SELECT: - outliner_flag_set(&soops->tree, TSE_SELECTED, 1); - break; - case SEL_DESELECT: - outliner_flag_set(&soops->tree, TSE_SELECTED, 0); - break; - case SEL_INVERT: - outliner_flag_flip(&soops->tree, TSE_SELECTED); - break; - } - - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - ED_region_tag_redraw_no_rebuild(ar); - - return OPERATOR_FINISHED; + SpaceOutliner *soops = CTX_wm_space_outliner(C); + ARegion *ar = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + int action = RNA_enum_get(op->ptr, "action"); + if (action == SEL_TOGGLE) { + action = outliner_flag_is_any_test(&soops->tree, TSE_SELECTED, 1) ? SEL_DESELECT : SEL_SELECT; + } + + switch (action) { + case SEL_SELECT: + outliner_flag_set(&soops->tree, TSE_SELECTED, 1); + break; + case SEL_DESELECT: + outliner_flag_set(&soops->tree, TSE_SELECTED, 0); + break; + case SEL_INVERT: + outliner_flag_flip(&soops->tree, TSE_SELECTED); + break; + } + + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + ED_region_tag_redraw_no_rebuild(ar); + + return OPERATOR_FINISHED; } void OUTLINER_OT_select_all(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Toggle Selected"; - ot->idname = "OUTLINER_OT_select_all"; - ot->description = "Toggle the Outliner selection of items"; + /* identifiers */ + ot->name = "Toggle Selected"; + ot->idname = "OUTLINER_OT_select_all"; + ot->description = "Toggle the Outliner selection of items"; - /* callbacks */ - ot->exec = outliner_select_all_exec; - ot->poll = ED_operator_outliner_active; + /* callbacks */ + ot->exec = outliner_select_all_exec; + ot->poll = ED_operator_outliner_active; - /* no undo or registry */ + /* no undo or registry */ - /* rna */ - WM_operator_properties_select_all(ot); + /* rna */ + WM_operator_properties_select_all(ot); } /* ************************************************************** */ @@ -1060,165 +1127,167 @@ void OUTLINER_OT_select_all(wmOperatorType *ot) /* Show Active --------------------------------------------------- */ -static void outliner_set_coordinates_element_recursive(SpaceOutliner *soops, TreeElement *te, int startx, int *starty) +static void outliner_set_coordinates_element_recursive(SpaceOutliner *soops, + TreeElement *te, + int startx, + int *starty) { - TreeStoreElem *tselem = TREESTORE(te); + TreeStoreElem *tselem = TREESTORE(te); - /* store coord and continue, we need coordinates for elements outside view too */ - te->xs = (float)startx; - te->ys = (float)(*starty); - *starty -= UI_UNIT_Y; + /* store coord and continue, we need coordinates for elements outside view too */ + te->xs = (float)startx; + te->ys = (float)(*starty); + *starty -= UI_UNIT_Y; - if (TSELEM_OPEN(tselem, soops)) { - TreeElement *ten; - for (ten = te->subtree.first; ten; ten = ten->next) { - outliner_set_coordinates_element_recursive(soops, ten, startx + UI_UNIT_X, starty); - } - } + if (TSELEM_OPEN(tselem, soops)) { + TreeElement *ten; + for (ten = te->subtree.first; ten; ten = ten->next) { + outliner_set_coordinates_element_recursive(soops, ten, startx + UI_UNIT_X, starty); + } + } } /* to retrieve coordinates with redrawing the entire tree */ void outliner_set_coordinates(ARegion *ar, SpaceOutliner *soops) { - TreeElement *te; - int starty = (int)(ar->v2d.tot.ymax) - UI_UNIT_Y; + TreeElement *te; + int starty = (int)(ar->v2d.tot.ymax) - UI_UNIT_Y; - for (te = soops->tree.first; te; te = te->next) { - outliner_set_coordinates_element_recursive(soops, te, 0, &starty); - } + for (te = soops->tree.first; te; te = te->next) { + outliner_set_coordinates_element_recursive(soops, te, 0, &starty); + } } /* return 1 when levels were opened */ static int outliner_open_back(TreeElement *te) { - TreeStoreElem *tselem; - int retval = 0; + TreeStoreElem *tselem; + int retval = 0; - for (te = te->parent; te; te = te->parent) { - tselem = TREESTORE(te); - if (tselem->flag & TSE_CLOSED) { - tselem->flag &= ~TSE_CLOSED; - retval = 1; - } - } - return retval; + for (te = te->parent; te; te = te->parent) { + tselem = TREESTORE(te); + if (tselem->flag & TSE_CLOSED) { + tselem->flag &= ~TSE_CLOSED; + retval = 1; + } + } + return retval; } static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op)) { - SpaceOutliner *so = CTX_wm_space_outliner(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - ARegion *ar = CTX_wm_region(C); - View2D *v2d = &ar->v2d; - - TreeElement *te; - int xdelta, ytop; + SpaceOutliner *so = CTX_wm_space_outliner(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + ARegion *ar = CTX_wm_region(C); + View2D *v2d = &ar->v2d; - Object *obact = OBACT(view_layer); + TreeElement *te; + int xdelta, ytop; - if (!obact) { - return OPERATOR_CANCELLED; - } + Object *obact = OBACT(view_layer); + if (!obact) { + return OPERATOR_CANCELLED; + } - te = outliner_find_id(so, &so->tree, &obact->id); + te = outliner_find_id(so, &so->tree, &obact->id); - if (te != NULL && obact->type == OB_ARMATURE) { - /* traverse down the bone hierarchy in case of armature */ - TreeElement *te_obact = te; + if (te != NULL && obact->type == OB_ARMATURE) { + /* traverse down the bone hierarchy in case of armature */ + TreeElement *te_obact = te; - if (obact->mode & OB_MODE_POSE) { - bPoseChannel *pchan = CTX_data_active_pose_bone(C); - if (pchan) { - te = outliner_find_posechannel(&te_obact->subtree, pchan); - } - } - else if (obact->mode & OB_MODE_EDIT) { - EditBone *ebone = CTX_data_active_bone(C); - if (ebone) { - te = outliner_find_editbone(&te_obact->subtree, ebone); - } - } - } + if (obact->mode & OB_MODE_POSE) { + bPoseChannel *pchan = CTX_data_active_pose_bone(C); + if (pchan) { + te = outliner_find_posechannel(&te_obact->subtree, pchan); + } + } + else if (obact->mode & OB_MODE_EDIT) { + EditBone *ebone = CTX_data_active_bone(C); + if (ebone) { + te = outliner_find_editbone(&te_obact->subtree, ebone); + } + } + } - if (te) { - /* open up tree to active object/bone */ - if (outliner_open_back(te)) { - outliner_set_coordinates(ar, so); - } + if (te) { + /* open up tree to active object/bone */ + if (outliner_open_back(te)) { + outliner_set_coordinates(ar, so); + } - /* make te->ys center of view */ - ytop = te->ys + BLI_rcti_size_y(&v2d->mask) / 2; - if (ytop > 0) { - ytop = 0; - } + /* make te->ys center of view */ + ytop = te->ys + BLI_rcti_size_y(&v2d->mask) / 2; + if (ytop > 0) { + ytop = 0; + } - v2d->cur.ymax = (float)ytop; - v2d->cur.ymin = (float)(ytop - BLI_rcti_size_y(&v2d->mask)); + v2d->cur.ymax = (float)ytop; + v2d->cur.ymin = (float)(ytop - BLI_rcti_size_y(&v2d->mask)); - /* make te->xs ==> te->xend center of view */ - xdelta = (int)(te->xs - v2d->cur.xmin); - v2d->cur.xmin += xdelta; - v2d->cur.xmax += xdelta; - } + /* make te->xs ==> te->xend center of view */ + xdelta = (int)(te->xs - v2d->cur.xmin); + v2d->cur.xmin += xdelta; + v2d->cur.xmax += xdelta; + } - ED_region_tag_redraw_no_rebuild(ar); + ED_region_tag_redraw_no_rebuild(ar); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_show_active(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Show Active"; - ot->idname = "OUTLINER_OT_show_active"; - ot->description = "Open up the tree and adjust the view so that the active Object is shown centered"; + /* identifiers */ + ot->name = "Show Active"; + ot->idname = "OUTLINER_OT_show_active"; + ot->description = + "Open up the tree and adjust the view so that the active Object is shown centered"; - /* callbacks */ - ot->exec = outliner_show_active_exec; - ot->poll = ED_operator_outliner_active; + /* callbacks */ + ot->exec = outliner_show_active_exec; + ot->poll = ED_operator_outliner_active; } /* View Panning --------------------------------------------------- */ static int outliner_scroll_page_exec(bContext *C, wmOperator *op) { - ARegion *ar = CTX_wm_region(C); - int dy = BLI_rcti_size_y(&ar->v2d.mask); - int up = 0; + ARegion *ar = CTX_wm_region(C); + int dy = BLI_rcti_size_y(&ar->v2d.mask); + int up = 0; - if (RNA_boolean_get(op->ptr, "up")) { - up = 1; - } + if (RNA_boolean_get(op->ptr, "up")) { + up = 1; + } - if (up == 0) { - dy = -dy; - } - ar->v2d.cur.ymin += dy; - ar->v2d.cur.ymax += dy; + if (up == 0) { + dy = -dy; + } + ar->v2d.cur.ymin += dy; + ar->v2d.cur.ymax += dy; - ED_region_tag_redraw_no_rebuild(ar); + ED_region_tag_redraw_no_rebuild(ar); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } - void OUTLINER_OT_scroll_page(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Scroll Page"; - ot->idname = "OUTLINER_OT_scroll_page"; - ot->description = "Scroll page up or down"; + /* identifiers */ + ot->name = "Scroll Page"; + ot->idname = "OUTLINER_OT_scroll_page"; + ot->description = "Scroll page up or down"; - /* callbacks */ - ot->exec = outliner_scroll_page_exec; - ot->poll = ED_operator_outliner_active; + /* callbacks */ + ot->exec = outliner_scroll_page_exec; + ot->poll = ED_operator_outliner_active; - /* properties */ - prop = RNA_def_boolean(ot->srna, "up", 0, "Up", "Scroll up one page"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* properties */ + prop = RNA_def_boolean(ot->srna, "up", 0, "Up", "Scroll up one page"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /* Search ------------------------------------------------------- */ @@ -1230,104 +1299,104 @@ void OUTLINER_OT_scroll_page(wmOperatorType *ot) static TreeElement *outliner_find_name(SpaceOutliner *soops, ListBase *lb, char *name, int flags, TreeElement *prev, int *prevFound) { - TreeElement *te, *tes; + TreeElement *te, *tes; - for (te = lb->first; te; te = te->next) { - int found = outliner_filter_has_name(te, name, flags); + for (te = lb->first; te; te = te->next) { + int found = outliner_filter_has_name(te, name, flags); - if (found) { - /* name is right, but is element the previous one? */ - if (prev) { - if ((te != prev) && (*prevFound)) - return te; - if (te == prev) { - *prevFound = 1; - } - } - else - return te; - } + if (found) { + /* name is right, but is element the previous one? */ + if (prev) { + if ((te != prev) && (*prevFound)) + return te; + if (te == prev) { + *prevFound = 1; + } + } + else + return te; + } - tes = outliner_find_name(soops, &te->subtree, name, flags, prev, prevFound); - if (tes) return tes; - } + tes = outliner_find_name(soops, &te->subtree, name, flags, prev, prevFound); + if (tes) return tes; + } - /* nothing valid found */ - return NULL; + /* nothing valid found */ + return NULL; } static void outliner_find_panel(Scene *UNUSED(scene), ARegion *ar, SpaceOutliner *soops, int again, int flags) { - ReportList *reports = NULL; // CTX_wm_reports(C); - TreeElement *te = NULL; - TreeElement *last_find; - TreeStoreElem *tselem; - int ytop, xdelta, prevFound = 0; - char name[sizeof(soops->search_string)]; - - /* get last found tree-element based on stored search_tse */ - last_find = outliner_find_tse(soops, &soops->search_tse); - - /* determine which type of search to do */ - if (again && last_find) { - /* no popup panel - previous + user wanted to search for next after previous */ - BLI_strncpy(name, soops->search_string, sizeof(name)); - flags = soops->search_flags; - - /* try to find matching element */ - te = outliner_find_name(soops, &soops->tree, name, flags, last_find, &prevFound); - if (te == NULL) { - /* no more matches after previous, start from beginning again */ - prevFound = 1; - te = outliner_find_name(soops, &soops->tree, name, flags, last_find, &prevFound); - } - } - else { - /* pop up panel - no previous, or user didn't want search after previous */ - name[0] = '\0'; -// XXX if (sbutton(name, 0, sizeof(name) - 1, "Find: ") && name[0]) { -// te = outliner_find_name(soops, &soops->tree, name, flags, NULL, &prevFound); -// } -// else return; /* XXX RETURN! XXX */ - } - - /* do selection and reveal */ - if (te) { - tselem = TREESTORE(te); - if (tselem) { - /* expand branches so that it will be visible, we need to get correct coordinates */ - if (outliner_open_back(soops, te)) - outliner_set_coordinates(ar, soops); - - /* deselect all visible, and select found element */ - outliner_flag_set(soops, &soops->tree, TSE_SELECTED, 0); - tselem->flag |= TSE_SELECTED; - - /* make te->ys center of view */ - ytop = (int)(te->ys + BLI_rctf_size_y(&ar->v2d.mask) / 2); - if (ytop > 0) ytop = 0; - ar->v2d.cur.ymax = (float)ytop; - ar->v2d.cur.ymin = (float)(ytop - BLI_rctf_size_y(&ar->v2d.mask)); - - /* make te->xs ==> te->xend center of view */ - xdelta = (int)(te->xs - ar->v2d.cur.xmin); - ar->v2d.cur.xmin += xdelta; - ar->v2d.cur.xmax += xdelta; - - /* store selection */ - soops->search_tse = *tselem; - - BLI_strncpy(soops->search_string, name, sizeof(soops->search_string)); - soops->search_flags = flags; - - /* redraw */ - ED_region_tag_redraw_no_rebuild(ar); - } - } - else { - /* no tree-element found */ - BKE_reportf(reports, RPT_WARNING, "Not found: %s", name); - } + ReportList *reports = NULL; // CTX_wm_reports(C); + TreeElement *te = NULL; + TreeElement *last_find; + TreeStoreElem *tselem; + int ytop, xdelta, prevFound = 0; + char name[sizeof(soops->search_string)]; + + /* get last found tree-element based on stored search_tse */ + last_find = outliner_find_tse(soops, &soops->search_tse); + + /* determine which type of search to do */ + if (again && last_find) { + /* no popup panel - previous + user wanted to search for next after previous */ + BLI_strncpy(name, soops->search_string, sizeof(name)); + flags = soops->search_flags; + + /* try to find matching element */ + te = outliner_find_name(soops, &soops->tree, name, flags, last_find, &prevFound); + if (te == NULL) { + /* no more matches after previous, start from beginning again */ + prevFound = 1; + te = outliner_find_name(soops, &soops->tree, name, flags, last_find, &prevFound); + } + } + else { + /* pop up panel - no previous, or user didn't want search after previous */ + name[0] = '\0'; +// XXX if (sbutton(name, 0, sizeof(name) - 1, "Find: ") && name[0]) { +// te = outliner_find_name(soops, &soops->tree, name, flags, NULL, &prevFound); +// } +// else return; /* XXX RETURN! XXX */ + } + + /* do selection and reveal */ + if (te) { + tselem = TREESTORE(te); + if (tselem) { + /* expand branches so that it will be visible, we need to get correct coordinates */ + if (outliner_open_back(soops, te)) + outliner_set_coordinates(ar, soops); + + /* deselect all visible, and select found element */ + outliner_flag_set(soops, &soops->tree, TSE_SELECTED, 0); + tselem->flag |= TSE_SELECTED; + + /* make te->ys center of view */ + ytop = (int)(te->ys + BLI_rctf_size_y(&ar->v2d.mask) / 2); + if (ytop > 0) ytop = 0; + ar->v2d.cur.ymax = (float)ytop; + ar->v2d.cur.ymin = (float)(ytop - BLI_rctf_size_y(&ar->v2d.mask)); + + /* make te->xs ==> te->xend center of view */ + xdelta = (int)(te->xs - ar->v2d.cur.xmin); + ar->v2d.cur.xmin += xdelta; + ar->v2d.cur.xmax += xdelta; + + /* store selection */ + soops->search_tse = *tselem; + + BLI_strncpy(soops->search_string, name, sizeof(soops->search_string)); + soops->search_flags = flags; + + /* redraw */ + ED_region_tag_redraw_no_rebuild(ar); + } + } + else { + /* no tree-element found */ + BKE_reportf(reports, RPT_WARNING, "Not found: %s", name); + } } #endif @@ -1336,72 +1405,72 @@ static void outliner_find_panel(Scene *UNUSED(scene), ARegion *ar, SpaceOutliner /* helper function for Show/Hide one level operator */ static void outliner_openclose_level(ListBase *lb, int curlevel, int level, int open) { - TreeElement *te; - TreeStoreElem *tselem; + TreeElement *te; + TreeStoreElem *tselem; - for (te = lb->first; te; te = te->next) { - tselem = TREESTORE(te); + for (te = lb->first; te; te = te->next) { + tselem = TREESTORE(te); - if (open) { - if (curlevel <= level) { - tselem->flag &= ~TSE_CLOSED; - } - } - else { - if (curlevel >= level) { - tselem->flag |= TSE_CLOSED; - } - } + if (open) { + if (curlevel <= level) { + tselem->flag &= ~TSE_CLOSED; + } + } + else { + if (curlevel >= level) { + tselem->flag |= TSE_CLOSED; + } + } - outliner_openclose_level(&te->subtree, curlevel + 1, level, open); - } + outliner_openclose_level(&te->subtree, curlevel + 1, level, open); + } } static int outliner_one_level_exec(bContext *C, wmOperator *op) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - ARegion *ar = CTX_wm_region(C); - const bool add = RNA_boolean_get(op->ptr, "open"); - int level; + SpaceOutliner *soops = CTX_wm_space_outliner(C); + ARegion *ar = CTX_wm_region(C); + const bool add = RNA_boolean_get(op->ptr, "open"); + int level; - level = outliner_flag_is_any_test(&soops->tree, TSE_CLOSED, 1); - if (add == 1) { - if (level) { - outliner_openclose_level(&soops->tree, 1, level, 1); - } - } - else { - if (level == 0) { - level = outliner_count_levels(&soops->tree, 0); - } - if (level) { - outliner_openclose_level(&soops->tree, 1, level - 1, 0); - } - } + level = outliner_flag_is_any_test(&soops->tree, TSE_CLOSED, 1); + if (add == 1) { + if (level) { + outliner_openclose_level(&soops->tree, 1, level, 1); + } + } + else { + if (level == 0) { + level = outliner_count_levels(&soops->tree, 0); + } + if (level) { + outliner_openclose_level(&soops->tree, 1, level - 1, 0); + } + } - ED_region_tag_redraw(ar); + ED_region_tag_redraw(ar); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_show_one_level(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Show/Hide One Level"; - ot->idname = "OUTLINER_OT_show_one_level"; - ot->description = "Expand/collapse all entries by one level"; + /* identifiers */ + ot->name = "Show/Hide One Level"; + ot->idname = "OUTLINER_OT_show_one_level"; + ot->description = "Expand/collapse all entries by one level"; - /* callbacks */ - ot->exec = outliner_one_level_exec; - ot->poll = ED_operator_outliner_active; + /* callbacks */ + ot->exec = outliner_one_level_exec; + ot->poll = ED_operator_outliner_active; - /* no undo or registry, UI option */ + /* no undo or registry, UI option */ - /* properties */ - prop = RNA_def_boolean(ot->srna, "open", 1, "Open", "Expand all entries one level deep"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); + /* properties */ + prop = RNA_def_boolean(ot->srna, "open", 1, "Open", "Expand all entries one level deep"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /* Show Hierarchy ----------------------------------------------- */ @@ -1409,86 +1478,86 @@ void OUTLINER_OT_show_one_level(wmOperatorType *ot) /* helper function for tree_element_shwo_hierarchy() - recursively checks whether subtrees have any objects*/ static int subtree_has_objects(ListBase *lb) { - TreeElement *te; - TreeStoreElem *tselem; + TreeElement *te; + TreeStoreElem *tselem; - for (te = lb->first; te; te = te->next) { - tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { - return 1; - } - if (subtree_has_objects(&te->subtree)) { - return 1; - } - } - return 0; + for (te = lb->first; te; te = te->next) { + tselem = TREESTORE(te); + if (tselem->type == 0 && te->idcode == ID_OB) { + return 1; + } + if (subtree_has_objects(&te->subtree)) { + return 1; + } + } + return 0; } /* recursive helper function for Show Hierarchy operator */ static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *soops, ListBase *lb) { - TreeElement *te; - TreeStoreElem *tselem; - - /* open all object elems, close others */ - for (te = lb->first; te; te = te->next) { - tselem = TREESTORE(te); - - if (tselem->type == 0) { - if (te->idcode == ID_SCE) { - if (tselem->id != (ID *)scene) { - tselem->flag |= TSE_CLOSED; - } - else { - tselem->flag &= ~TSE_CLOSED; - } - } - else if (te->idcode == ID_OB) { - if (subtree_has_objects(&te->subtree)) { - tselem->flag &= ~TSE_CLOSED; - } - else { - tselem->flag |= TSE_CLOSED; - } - } - } - else { - tselem->flag |= TSE_CLOSED; - } - - if (TSELEM_OPEN(tselem, soops)) { - tree_element_show_hierarchy(scene, soops, &te->subtree); - } - } + TreeElement *te; + TreeStoreElem *tselem; + + /* open all object elems, close others */ + for (te = lb->first; te; te = te->next) { + tselem = TREESTORE(te); + + if (tselem->type == 0) { + if (te->idcode == ID_SCE) { + if (tselem->id != (ID *)scene) { + tselem->flag |= TSE_CLOSED; + } + else { + tselem->flag &= ~TSE_CLOSED; + } + } + else if (te->idcode == ID_OB) { + if (subtree_has_objects(&te->subtree)) { + tselem->flag &= ~TSE_CLOSED; + } + else { + tselem->flag |= TSE_CLOSED; + } + } + } + else { + tselem->flag |= TSE_CLOSED; + } + + if (TSELEM_OPEN(tselem, soops)) { + tree_element_show_hierarchy(scene, soops, &te->subtree); + } + } } /* show entire object level hierarchy */ static int outliner_show_hierarchy_exec(bContext *C, wmOperator *UNUSED(op)) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - ARegion *ar = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + ARegion *ar = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); - /* recursively open/close levels */ - tree_element_show_hierarchy(scene, soops, &soops->tree); + /* recursively open/close levels */ + tree_element_show_hierarchy(scene, soops, &soops->tree); - ED_region_tag_redraw(ar); + ED_region_tag_redraw(ar); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_show_hierarchy(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Show Hierarchy"; - ot->idname = "OUTLINER_OT_show_hierarchy"; - ot->description = "Open all object entries and close all others"; + /* identifiers */ + ot->name = "Show Hierarchy"; + ot->idname = "OUTLINER_OT_show_hierarchy"; + ot->description = "Open all object entries and close all others"; - /* callbacks */ - ot->exec = outliner_show_hierarchy_exec; - ot->poll = ED_operator_outliner_active; // TODO: shouldn't be allowed in RNA views... + /* callbacks */ + ot->exec = outliner_show_hierarchy_exec; + ot->poll = ED_operator_outliner_active; // TODO: shouldn't be allowed in RNA views... - /* no undo or registry, UI option */ + /* no undo or registry, UI option */ } /* ************************************************************** */ @@ -1498,157 +1567,161 @@ void OUTLINER_OT_show_hierarchy(wmOperatorType *ot) /* specialized poll callback for these operators to work in Datablocks view only */ static bool ed_operator_outliner_datablocks_active(bContext *C) { - ScrArea *sa = CTX_wm_area(C); - if ((sa) && (sa->spacetype == SPACE_OUTLINER)) { - SpaceOutliner *so = CTX_wm_space_outliner(C); - return (so->outlinevis == SO_DATA_API); - } - return 0; + ScrArea *sa = CTX_wm_area(C); + if ((sa) && (sa->spacetype == SPACE_OUTLINER)) { + SpaceOutliner *so = CTX_wm_space_outliner(C); + return (so->outlinevis == SO_DATA_API); + } + return 0; } - /* Helper func to extract an RNA path from selected tree element * NOTE: the caller must zero-out all values of the pointers that it passes here first, as * this function does not do that yet */ -static void tree_element_to_path(TreeElement *te, TreeStoreElem *tselem, - ID **id, char **path, int *array_index, short *flag, short *UNUSED(groupmode)) -{ - ListBase hierarchy = {NULL, NULL}; - LinkData *ld; - TreeElement *tem, *temnext, *temsub; - TreeStoreElem *tse /* , *tsenext */ /* UNUSED */; - PointerRNA *ptr, *nextptr; - PropertyRNA *prop; - char *newpath = NULL; - - /* optimize tricks: - * - Don't do anything if the selected item is a 'struct', but arrays are allowed - */ - if (tselem->type == TSE_RNA_STRUCT) { - return; - } - - /* Overview of Algorithm: - * 1. Go up the chain of parents until we find the 'root', taking note of the - * levels encountered in reverse-order (i.e. items are added to the start of the list - * for more convenient looping later) - * 2. Walk down the chain, adding from the first ID encountered - * (which will become the 'ID' for the KeyingSet Path), and build a - * path as we step through the chain - */ - - /* step 1: flatten out hierarchy of parents into a flat chain */ - for (tem = te->parent; tem; tem = tem->parent) { - ld = MEM_callocN(sizeof(LinkData), "LinkData for tree_element_to_path()"); - ld->data = tem; - BLI_addhead(&hierarchy, ld); - } - - /* step 2: step down hierarchy building the path - * (NOTE: addhead in previous loop was needed so that we can loop like this) */ - for (ld = hierarchy.first; ld; ld = ld->next) { - /* get data */ - tem = (TreeElement *)ld->data; - tse = TREESTORE(tem); - ptr = &tem->rnaptr; - prop = tem->directdata; - - /* check if we're looking for first ID, or appending to path */ - if (*id) { - /* just 'append' property to path - * - to prevent memory leaks, we must write to newpath not path, then free old path + swap them - */ - if (tse->type == TSE_RNA_PROPERTY) { - if (RNA_property_type(prop) == PROP_POINTER) { - /* for pointer we just append property name */ - newpath = RNA_path_append(*path, ptr, prop, 0, NULL); - } - else if (RNA_property_type(prop) == PROP_COLLECTION) { - char buf[128], *name; - - temnext = (TreeElement *)(ld->next->data); - /* tsenext = TREESTORE(temnext); */ /* UNUSED */ - - nextptr = &temnext->rnaptr; - name = RNA_struct_name_get_alloc(nextptr, buf, sizeof(buf), NULL); - - if (name) { - /* if possible, use name as a key in the path */ - newpath = RNA_path_append(*path, NULL, prop, 0, name); - - if (name != buf) { - MEM_freeN(name); - } - } - else { - /* otherwise use index */ - int index = 0; - - for (temsub = tem->subtree.first; temsub; temsub = temsub->next, index++) { - if (temsub == temnext) { - break; - } - } - newpath = RNA_path_append(*path, NULL, prop, index, NULL); - } - - ld = ld->next; - } - } - - if (newpath) { - if (*path) { - MEM_freeN(*path); - } - *path = newpath; - newpath = NULL; - } - } - else { - /* no ID, so check if entry is RNA-struct, and if that RNA-struct is an ID datablock to extract info from */ - if (tse->type == TSE_RNA_STRUCT) { - /* ptr->data not ptr->id.data seems to be the one we want, - * since ptr->data is sometimes the owner of this ID? */ - if (RNA_struct_is_ID(ptr->type)) { - *id = (ID *)ptr->data; - - /* clear path */ - if (*path) { - MEM_freeN(*path); - path = NULL; - } - } - } - } - } - - /* step 3: if we've got an ID, add the current item to the path */ - if (*id) { - /* add the active property to the path */ - ptr = &te->rnaptr; - prop = te->directdata; - - /* array checks */ - if (tselem->type == TSE_RNA_ARRAY_ELEM) { - /* item is part of an array, so must set the array_index */ - *array_index = te->index; - } - else if (RNA_property_array_check(prop)) { - /* entire array was selected, so keyframe all */ - *flag |= KSP_FLAG_WHOLE_ARRAY; - } - - /* path */ - newpath = RNA_path_append(*path, NULL, prop, 0, NULL); - if (*path) { - MEM_freeN(*path); - } - *path = newpath; - } - - /* free temp data */ - BLI_freelistN(&hierarchy); +static void tree_element_to_path(TreeElement *te, + TreeStoreElem *tselem, + ID **id, + char **path, + int *array_index, + short *flag, + short *UNUSED(groupmode)) +{ + ListBase hierarchy = {NULL, NULL}; + LinkData *ld; + TreeElement *tem, *temnext, *temsub; + TreeStoreElem *tse /* , *tsenext */ /* UNUSED */; + PointerRNA *ptr, *nextptr; + PropertyRNA *prop; + char *newpath = NULL; + + /* optimize tricks: + * - Don't do anything if the selected item is a 'struct', but arrays are allowed + */ + if (tselem->type == TSE_RNA_STRUCT) { + return; + } + + /* Overview of Algorithm: + * 1. Go up the chain of parents until we find the 'root', taking note of the + * levels encountered in reverse-order (i.e. items are added to the start of the list + * for more convenient looping later) + * 2. Walk down the chain, adding from the first ID encountered + * (which will become the 'ID' for the KeyingSet Path), and build a + * path as we step through the chain + */ + + /* step 1: flatten out hierarchy of parents into a flat chain */ + for (tem = te->parent; tem; tem = tem->parent) { + ld = MEM_callocN(sizeof(LinkData), "LinkData for tree_element_to_path()"); + ld->data = tem; + BLI_addhead(&hierarchy, ld); + } + + /* step 2: step down hierarchy building the path + * (NOTE: addhead in previous loop was needed so that we can loop like this) */ + for (ld = hierarchy.first; ld; ld = ld->next) { + /* get data */ + tem = (TreeElement *)ld->data; + tse = TREESTORE(tem); + ptr = &tem->rnaptr; + prop = tem->directdata; + + /* check if we're looking for first ID, or appending to path */ + if (*id) { + /* just 'append' property to path + * - to prevent memory leaks, we must write to newpath not path, then free old path + swap them + */ + if (tse->type == TSE_RNA_PROPERTY) { + if (RNA_property_type(prop) == PROP_POINTER) { + /* for pointer we just append property name */ + newpath = RNA_path_append(*path, ptr, prop, 0, NULL); + } + else if (RNA_property_type(prop) == PROP_COLLECTION) { + char buf[128], *name; + + temnext = (TreeElement *)(ld->next->data); + /* tsenext = TREESTORE(temnext); */ /* UNUSED */ + + nextptr = &temnext->rnaptr; + name = RNA_struct_name_get_alloc(nextptr, buf, sizeof(buf), NULL); + + if (name) { + /* if possible, use name as a key in the path */ + newpath = RNA_path_append(*path, NULL, prop, 0, name); + + if (name != buf) { + MEM_freeN(name); + } + } + else { + /* otherwise use index */ + int index = 0; + + for (temsub = tem->subtree.first; temsub; temsub = temsub->next, index++) { + if (temsub == temnext) { + break; + } + } + newpath = RNA_path_append(*path, NULL, prop, index, NULL); + } + + ld = ld->next; + } + } + + if (newpath) { + if (*path) { + MEM_freeN(*path); + } + *path = newpath; + newpath = NULL; + } + } + else { + /* no ID, so check if entry is RNA-struct, and if that RNA-struct is an ID datablock to extract info from */ + if (tse->type == TSE_RNA_STRUCT) { + /* ptr->data not ptr->id.data seems to be the one we want, + * since ptr->data is sometimes the owner of this ID? */ + if (RNA_struct_is_ID(ptr->type)) { + *id = (ID *)ptr->data; + + /* clear path */ + if (*path) { + MEM_freeN(*path); + path = NULL; + } + } + } + } + } + + /* step 3: if we've got an ID, add the current item to the path */ + if (*id) { + /* add the active property to the path */ + ptr = &te->rnaptr; + prop = te->directdata; + + /* array checks */ + if (tselem->type == TSE_RNA_ARRAY_ELEM) { + /* item is part of an array, so must set the array_index */ + *array_index = te->index; + } + else if (RNA_property_array_check(prop)) { + /* entire array was selected, so keyframe all */ + *flag |= KSP_FLAG_WHOLE_ARRAY; + } + + /* path */ + newpath = RNA_path_append(*path, NULL, prop, 0, NULL); + if (*path) { + MEM_freeN(*path); + } + *path = newpath; + } + + /* free temp data */ + BLI_freelistN(&hierarchy); } /* =============================================== */ @@ -1658,159 +1731,155 @@ static void tree_element_to_path(TreeElement *te, TreeStoreElem *tselem, * they depend on having RNA paths and/or hierarchies available. */ enum { - DRIVERS_EDITMODE_ADD = 0, - DRIVERS_EDITMODE_REMOVE, + DRIVERS_EDITMODE_ADD = 0, + DRIVERS_EDITMODE_REMOVE, } /*eDrivers_EditModes*/; /* Utilities ---------------------------------- */ /* Recursively iterate over tree, finding and working on selected items */ -static void do_outliner_drivers_editop(SpaceOutliner *soops, ListBase *tree, ReportList *reports, short mode) -{ - TreeElement *te; - TreeStoreElem *tselem; - - for (te = tree->first; te; te = te->next) { - tselem = TREESTORE(te); - - /* if item is selected, perform operation */ - if (tselem->flag & TSE_SELECTED) { - ID *id = NULL; - char *path = NULL; - int array_index = 0; - short flag = 0; - short groupmode = KSP_GROUP_KSNAME; - - /* check if RNA-property described by this selected element is an animatable prop */ - if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) && - RNA_property_animateable(&te->rnaptr, te->directdata)) - { - /* get id + path + index info from the selected element */ - tree_element_to_path(te, tselem, - &id, &path, &array_index, &flag, &groupmode); - } - - /* only if ID and path were set, should we perform any actions */ - if (id && path) { - short dflags = CREATEDRIVER_WITH_DEFAULT_DVAR; - int arraylen = 1; - - /* array checks */ - if (flag & KSP_FLAG_WHOLE_ARRAY) { - /* entire array was selected, so add drivers for all */ - arraylen = RNA_property_array_length(&te->rnaptr, te->directdata); - } - else { - arraylen = array_index; - } - - /* we should do at least one step */ - if (arraylen == array_index) { - arraylen++; - } - - /* for each array element we should affect, add driver */ - for (; array_index < arraylen; array_index++) { - /* action depends on mode */ - switch (mode) { - case DRIVERS_EDITMODE_ADD: - { - /* add a new driver with the information obtained (only if valid) */ - ANIM_add_driver(reports, id, path, array_index, dflags, DRIVER_TYPE_PYTHON); - break; - } - case DRIVERS_EDITMODE_REMOVE: - { - /* remove driver matching the information obtained (only if valid) */ - ANIM_remove_driver(reports, id, path, array_index, dflags); - break; - } - } - } - - /* free path, since it had to be generated */ - MEM_freeN(path); - } - - - } - - /* go over sub-tree */ - if (TSELEM_OPEN(tselem, soops)) { - do_outliner_drivers_editop(soops, &te->subtree, reports, mode); - } - } +static void do_outliner_drivers_editop(SpaceOutliner *soops, + ListBase *tree, + ReportList *reports, + short mode) +{ + TreeElement *te; + TreeStoreElem *tselem; + + for (te = tree->first; te; te = te->next) { + tselem = TREESTORE(te); + + /* if item is selected, perform operation */ + if (tselem->flag & TSE_SELECTED) { + ID *id = NULL; + char *path = NULL; + int array_index = 0; + short flag = 0; + short groupmode = KSP_GROUP_KSNAME; + + /* check if RNA-property described by this selected element is an animatable prop */ + if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) && + RNA_property_animateable(&te->rnaptr, te->directdata)) { + /* get id + path + index info from the selected element */ + tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode); + } + + /* only if ID and path were set, should we perform any actions */ + if (id && path) { + short dflags = CREATEDRIVER_WITH_DEFAULT_DVAR; + int arraylen = 1; + + /* array checks */ + if (flag & KSP_FLAG_WHOLE_ARRAY) { + /* entire array was selected, so add drivers for all */ + arraylen = RNA_property_array_length(&te->rnaptr, te->directdata); + } + else { + arraylen = array_index; + } + + /* we should do at least one step */ + if (arraylen == array_index) { + arraylen++; + } + + /* for each array element we should affect, add driver */ + for (; array_index < arraylen; array_index++) { + /* action depends on mode */ + switch (mode) { + case DRIVERS_EDITMODE_ADD: { + /* add a new driver with the information obtained (only if valid) */ + ANIM_add_driver(reports, id, path, array_index, dflags, DRIVER_TYPE_PYTHON); + break; + } + case DRIVERS_EDITMODE_REMOVE: { + /* remove driver matching the information obtained (only if valid) */ + ANIM_remove_driver(reports, id, path, array_index, dflags); + break; + } + } + } + + /* free path, since it had to be generated */ + MEM_freeN(path); + } + } + + /* go over sub-tree */ + if (TSELEM_OPEN(tselem, soops)) { + do_outliner_drivers_editop(soops, &te->subtree, reports, mode); + } + } } /* Add Operator ---------------------------------- */ static int outliner_drivers_addsel_exec(bContext *C, wmOperator *op) { - SpaceOutliner *soutliner = CTX_wm_space_outliner(C); + SpaceOutliner *soutliner = CTX_wm_space_outliner(C); - /* check for invalid states */ - if (soutliner == NULL) { - return OPERATOR_CANCELLED; - } + /* check for invalid states */ + if (soutliner == NULL) { + return OPERATOR_CANCELLED; + } - /* recursively go into tree, adding selected items */ - do_outliner_drivers_editop(soutliner, &soutliner->tree, op->reports, DRIVERS_EDITMODE_ADD); + /* recursively go into tree, adding selected items */ + do_outliner_drivers_editop(soutliner, &soutliner->tree, op->reports, DRIVERS_EDITMODE_ADD); - /* send notifiers */ - WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX + /* send notifiers */ + WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); // XXX - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_drivers_add_selected(wmOperatorType *ot) { - /* api callbacks */ - ot->idname = "OUTLINER_OT_drivers_add_selected"; - ot->name = "Add Drivers for Selected"; - ot->description = "Add drivers to selected items"; + /* api callbacks */ + ot->idname = "OUTLINER_OT_drivers_add_selected"; + ot->name = "Add Drivers for Selected"; + ot->description = "Add drivers to selected items"; - /* api callbacks */ - ot->exec = outliner_drivers_addsel_exec; - ot->poll = ed_operator_outliner_datablocks_active; + /* api callbacks */ + ot->exec = outliner_drivers_addsel_exec; + ot->poll = ed_operator_outliner_datablocks_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } - /* Remove Operator ---------------------------------- */ static int outliner_drivers_deletesel_exec(bContext *C, wmOperator *op) { - SpaceOutliner *soutliner = CTX_wm_space_outliner(C); + SpaceOutliner *soutliner = CTX_wm_space_outliner(C); - /* check for invalid states */ - if (soutliner == NULL) { - return OPERATOR_CANCELLED; - } + /* check for invalid states */ + if (soutliner == NULL) { + return OPERATOR_CANCELLED; + } - /* recursively go into tree, adding selected items */ - do_outliner_drivers_editop(soutliner, &soutliner->tree, op->reports, DRIVERS_EDITMODE_REMOVE); + /* recursively go into tree, adding selected items */ + do_outliner_drivers_editop(soutliner, &soutliner->tree, op->reports, DRIVERS_EDITMODE_REMOVE); - /* send notifiers */ - WM_event_add_notifier(C, ND_KEYS, NULL); // XXX + /* send notifiers */ + WM_event_add_notifier(C, ND_KEYS, NULL); // XXX - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_drivers_delete_selected(wmOperatorType *ot) { - /* identifiers */ - ot->idname = "OUTLINER_OT_drivers_delete_selected"; - ot->name = "Delete Drivers for Selected"; - ot->description = "Delete drivers assigned to selected items"; + /* identifiers */ + ot->idname = "OUTLINER_OT_drivers_delete_selected"; + ot->name = "Delete Drivers for Selected"; + ot->description = "Delete drivers assigned to selected items"; - /* api callbacks */ - ot->exec = outliner_drivers_deletesel_exec; - ot->poll = ed_operator_outliner_datablocks_active; + /* api callbacks */ + ot->exec = outliner_drivers_deletesel_exec; + ot->poll = ed_operator_outliner_datablocks_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* =============================================== */ @@ -1820,8 +1889,8 @@ void OUTLINER_OT_drivers_delete_selected(wmOperatorType *ot) * they depend on having RNA paths and/or hierarchies available. */ enum { - KEYINGSET_EDITMODE_ADD = 0, - KEYINGSET_EDITMODE_REMOVE, + KEYINGSET_EDITMODE_ADD = 0, + KEYINGSET_EDITMODE_REMOVE, } /*eKeyingSet_EditModes*/; /* Utilities ---------------------------------- */ @@ -1830,300 +1899,298 @@ enum { // TODO: should this be an API func? static KeyingSet *verify_active_keyingset(Scene *scene, short add) { - KeyingSet *ks = NULL; + KeyingSet *ks = NULL; - /* sanity check */ - if (scene == NULL) { - return NULL; - } + /* sanity check */ + if (scene == NULL) { + return NULL; + } - /* try to find one from scene */ - if (scene->active_keyingset > 0) { - ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); - } + /* try to find one from scene */ + if (scene->active_keyingset > 0) { + ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); + } - /* add if none found */ - // XXX the default settings have yet to evolve - if ((add) && (ks == NULL)) { - ks = BKE_keyingset_add(&scene->keyingsets, NULL, NULL, KEYINGSET_ABSOLUTE, 0); - scene->active_keyingset = BLI_listbase_count(&scene->keyingsets); - } + /* add if none found */ + // XXX the default settings have yet to evolve + if ((add) && (ks == NULL)) { + ks = BKE_keyingset_add(&scene->keyingsets, NULL, NULL, KEYINGSET_ABSOLUTE, 0); + scene->active_keyingset = BLI_listbase_count(&scene->keyingsets); + } - return ks; + return ks; } /* Recursively iterate over tree, finding and working on selected items */ -static void do_outliner_keyingset_editop(SpaceOutliner *soops, KeyingSet *ks, ListBase *tree, short mode) -{ - TreeElement *te; - TreeStoreElem *tselem; - - for (te = tree->first; te; te = te->next) { - tselem = TREESTORE(te); - - /* if item is selected, perform operation */ - if (tselem->flag & TSE_SELECTED) { - ID *id = NULL; - char *path = NULL; - int array_index = 0; - short flag = 0; - short groupmode = KSP_GROUP_KSNAME; - - /* check if RNA-property described by this selected element is an animatable prop */ - if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) && - RNA_property_animateable(&te->rnaptr, te->directdata)) - { - /* get id + path + index info from the selected element */ - tree_element_to_path(te, tselem, - &id, &path, &array_index, &flag, &groupmode); - } - - /* only if ID and path were set, should we perform any actions */ - if (id && path) { - /* action depends on mode */ - switch (mode) { - case KEYINGSET_EDITMODE_ADD: - { - /* add a new path with the information obtained (only if valid) */ - /* TODO: what do we do with group name? - * for now, we don't supply one, and just let this use the KeyingSet name */ - BKE_keyingset_add_path(ks, id, NULL, path, array_index, flag, groupmode); - ks->active_path = BLI_listbase_count(&ks->paths); - break; - } - case KEYINGSET_EDITMODE_REMOVE: - { - /* find the relevant path, then remove it from the KeyingSet */ - KS_Path *ksp = BKE_keyingset_find_path(ks, id, NULL, path, array_index, groupmode); - - if (ksp) { - /* free path's data */ - BKE_keyingset_free_path(ks, ksp); - - ks->active_path = 0; - } - break; - } - } - - /* free path, since it had to be generated */ - MEM_freeN(path); - } - } - - /* go over sub-tree */ - if (TSELEM_OPEN(tselem, soops)) { - do_outliner_keyingset_editop(soops, ks, &te->subtree, mode); - } - } +static void do_outliner_keyingset_editop(SpaceOutliner *soops, + KeyingSet *ks, + ListBase *tree, + short mode) +{ + TreeElement *te; + TreeStoreElem *tselem; + + for (te = tree->first; te; te = te->next) { + tselem = TREESTORE(te); + + /* if item is selected, perform operation */ + if (tselem->flag & TSE_SELECTED) { + ID *id = NULL; + char *path = NULL; + int array_index = 0; + short flag = 0; + short groupmode = KSP_GROUP_KSNAME; + + /* check if RNA-property described by this selected element is an animatable prop */ + if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) && + RNA_property_animateable(&te->rnaptr, te->directdata)) { + /* get id + path + index info from the selected element */ + tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode); + } + + /* only if ID and path were set, should we perform any actions */ + if (id && path) { + /* action depends on mode */ + switch (mode) { + case KEYINGSET_EDITMODE_ADD: { + /* add a new path with the information obtained (only if valid) */ + /* TODO: what do we do with group name? + * for now, we don't supply one, and just let this use the KeyingSet name */ + BKE_keyingset_add_path(ks, id, NULL, path, array_index, flag, groupmode); + ks->active_path = BLI_listbase_count(&ks->paths); + break; + } + case KEYINGSET_EDITMODE_REMOVE: { + /* find the relevant path, then remove it from the KeyingSet */ + KS_Path *ksp = BKE_keyingset_find_path(ks, id, NULL, path, array_index, groupmode); + + if (ksp) { + /* free path's data */ + BKE_keyingset_free_path(ks, ksp); + + ks->active_path = 0; + } + break; + } + } + + /* free path, since it had to be generated */ + MEM_freeN(path); + } + } + + /* go over sub-tree */ + if (TSELEM_OPEN(tselem, soops)) { + do_outliner_keyingset_editop(soops, ks, &te->subtree, mode); + } + } } /* Add Operator ---------------------------------- */ static int outliner_keyingset_additems_exec(bContext *C, wmOperator *op) { - SpaceOutliner *soutliner = CTX_wm_space_outliner(C); - Scene *scene = CTX_data_scene(C); - KeyingSet *ks = verify_active_keyingset(scene, 1); + SpaceOutliner *soutliner = CTX_wm_space_outliner(C); + Scene *scene = CTX_data_scene(C); + KeyingSet *ks = verify_active_keyingset(scene, 1); - /* check for invalid states */ - if (ks == NULL) { - BKE_report(op->reports, RPT_ERROR, "Operation requires an active keying set"); - return OPERATOR_CANCELLED; - } - if (soutliner == NULL) { - return OPERATOR_CANCELLED; - } + /* check for invalid states */ + if (ks == NULL) { + BKE_report(op->reports, RPT_ERROR, "Operation requires an active keying set"); + return OPERATOR_CANCELLED; + } + if (soutliner == NULL) { + return OPERATOR_CANCELLED; + } - /* recursively go into tree, adding selected items */ - do_outliner_keyingset_editop(soutliner, ks, &soutliner->tree, KEYINGSET_EDITMODE_ADD); + /* recursively go into tree, adding selected items */ + do_outliner_keyingset_editop(soutliner, ks, &soutliner->tree, KEYINGSET_EDITMODE_ADD); - /* send notifiers */ - WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); + /* send notifiers */ + WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_keyingset_add_selected(wmOperatorType *ot) { - /* identifiers */ - ot->idname = "OUTLINER_OT_keyingset_add_selected"; - ot->name = "Keying Set Add Selected"; - ot->description = "Add selected items (blue-gray rows) to active Keying Set"; + /* identifiers */ + ot->idname = "OUTLINER_OT_keyingset_add_selected"; + ot->name = "Keying Set Add Selected"; + ot->description = "Add selected items (blue-gray rows) to active Keying Set"; - /* api callbacks */ - ot->exec = outliner_keyingset_additems_exec; - ot->poll = ed_operator_outliner_datablocks_active; + /* api callbacks */ + ot->exec = outliner_keyingset_additems_exec; + ot->poll = ed_operator_outliner_datablocks_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } - /* Remove Operator ---------------------------------- */ static int outliner_keyingset_removeitems_exec(bContext *C, wmOperator *UNUSED(op)) { - SpaceOutliner *soutliner = CTX_wm_space_outliner(C); - Scene *scene = CTX_data_scene(C); - KeyingSet *ks = verify_active_keyingset(scene, 1); + SpaceOutliner *soutliner = CTX_wm_space_outliner(C); + Scene *scene = CTX_data_scene(C); + KeyingSet *ks = verify_active_keyingset(scene, 1); - /* check for invalid states */ - if (soutliner == NULL) { - return OPERATOR_CANCELLED; - } + /* check for invalid states */ + if (soutliner == NULL) { + return OPERATOR_CANCELLED; + } - /* recursively go into tree, adding selected items */ - do_outliner_keyingset_editop(soutliner, ks, &soutliner->tree, KEYINGSET_EDITMODE_REMOVE); + /* recursively go into tree, adding selected items */ + do_outliner_keyingset_editop(soutliner, ks, &soutliner->tree, KEYINGSET_EDITMODE_REMOVE); - /* send notifiers */ - WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); + /* send notifiers */ + WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot) { - /* identifiers */ - ot->idname = "OUTLINER_OT_keyingset_remove_selected"; - ot->name = "Keying Set Remove Selected"; - ot->description = "Remove selected items (blue-gray rows) from active Keying Set"; + /* identifiers */ + ot->idname = "OUTLINER_OT_keyingset_remove_selected"; + ot->name = "Keying Set Remove Selected"; + ot->description = "Remove selected items (blue-gray rows) from active Keying Set"; - /* api callbacks */ - ot->exec = outliner_keyingset_removeitems_exec; - ot->poll = ed_operator_outliner_datablocks_active; + /* api callbacks */ + ot->exec = outliner_keyingset_removeitems_exec; + ot->poll = ed_operator_outliner_datablocks_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } - /* ************************************************************** */ /* ORPHANED DATABLOCKS */ static bool ed_operator_outliner_id_orphans_active(bContext *C) { - ScrArea *sa = CTX_wm_area(C); - if ((sa) && (sa->spacetype == SPACE_OUTLINER)) { - SpaceOutliner *so = CTX_wm_space_outliner(C); - return (so->outlinevis == SO_ID_ORPHANS); - } - return 0; + ScrArea *sa = CTX_wm_area(C); + if ((sa) && (sa->spacetype == SPACE_OUTLINER)) { + SpaceOutliner *so = CTX_wm_space_outliner(C); + return (so->outlinevis == SO_ID_ORPHANS); + } + return 0; } /* Purge Orphans Operator --------------------------------------- */ static void outliner_orphans_purge_tag(ID *id, int *num_tagged) { - if (id->us == 0) { - id->tag |= LIB_TAG_DOIT; - num_tagged[INDEX_ID_NULL]++; - num_tagged[BKE_idcode_to_index(GS(id->name))]++; - } - else { - id->tag &= ~LIB_TAG_DOIT; - } + if (id->us == 0) { + id->tag |= LIB_TAG_DOIT; + num_tagged[INDEX_ID_NULL]++; + num_tagged[BKE_idcode_to_index(GS(id->name))]++; + } + else { + id->tag &= ~LIB_TAG_DOIT; + } } static int outliner_orphans_purge_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(evt)) { - Main *bmain = CTX_data_main(C); - int num_tagged[INDEX_ID_MAX] = {0}; - - /* Tag all IDs having zero users. */ - ID *id; - FOREACH_MAIN_ID_BEGIN(bmain, id) - { - outliner_orphans_purge_tag(id, num_tagged); - } - FOREACH_MAIN_ID_END; - RNA_int_set(op->ptr, "num_deleted", num_tagged[INDEX_ID_NULL]); - - if (num_tagged[INDEX_ID_NULL] == 0) { - BKE_report(op->reports, RPT_INFO, "No orphanned data-blocks to purge"); - return OPERATOR_CANCELLED; - } - - DynStr *dyn_str = BLI_dynstr_new(); - BLI_dynstr_append(dyn_str, "Purging unused data-blocks ("); - bool is_first = true; - for (int i = 0; i < INDEX_ID_MAX - 2; i++) { - if (num_tagged[i] != 0) { - if (!is_first) { - BLI_dynstr_append(dyn_str, ", "); - } - else { - is_first = false; - } - BLI_dynstr_appendf( - dyn_str, "%d %s", - num_tagged[i], TIP_(BKE_idcode_to_name_plural(BKE_idcode_from_index(i)))); - } - } - BLI_dynstr_append(dyn_str, TIP_("). Click here to proceed...")); - - char *message = BLI_dynstr_get_cstring(dyn_str); - int ret = WM_operator_confirm_message(C, op, message); - - MEM_freeN(message); - BLI_dynstr_free(dyn_str); - return ret; + Main *bmain = CTX_data_main(C); + int num_tagged[INDEX_ID_MAX] = {0}; + + /* Tag all IDs having zero users. */ + ID *id; + FOREACH_MAIN_ID_BEGIN(bmain, id) + { + outliner_orphans_purge_tag(id, num_tagged); + } + FOREACH_MAIN_ID_END; + RNA_int_set(op->ptr, "num_deleted", num_tagged[INDEX_ID_NULL]); + + if (num_tagged[INDEX_ID_NULL] == 0) { + BKE_report(op->reports, RPT_INFO, "No orphanned data-blocks to purge"); + return OPERATOR_CANCELLED; + } + + DynStr *dyn_str = BLI_dynstr_new(); + BLI_dynstr_append(dyn_str, "Purging unused data-blocks ("); + bool is_first = true; + for (int i = 0; i < INDEX_ID_MAX - 2; i++) { + if (num_tagged[i] != 0) { + if (!is_first) { + BLI_dynstr_append(dyn_str, ", "); + } + else { + is_first = false; + } + BLI_dynstr_appendf(dyn_str, + "%d %s", + num_tagged[i], + TIP_(BKE_idcode_to_name_plural(BKE_idcode_from_index(i)))); + } + } + BLI_dynstr_append(dyn_str, TIP_("). Click here to proceed...")); + + char *message = BLI_dynstr_get_cstring(dyn_str); + int ret = WM_operator_confirm_message(C, op, message); + + MEM_freeN(message); + BLI_dynstr_free(dyn_str); + return ret; } static int outliner_orphans_purge_exec(bContext *C, wmOperator *op) { - Main *bmain = CTX_data_main(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - int num_tagged[INDEX_ID_MAX] = {0}; + Main *bmain = CTX_data_main(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + int num_tagged[INDEX_ID_MAX] = {0}; - if ((num_tagged[INDEX_ID_NULL] = RNA_int_get(op->ptr, "num_deleted")) == 0) { - /* Tag all IDs having zero users. */ - ID *id; - FOREACH_MAIN_ID_BEGIN(bmain, id) - { - outliner_orphans_purge_tag(id, num_tagged); - } - FOREACH_MAIN_ID_END; + if ((num_tagged[INDEX_ID_NULL] = RNA_int_get(op->ptr, "num_deleted")) == 0) { + /* Tag all IDs having zero users. */ + ID *id; + FOREACH_MAIN_ID_BEGIN(bmain, id) + { + outliner_orphans_purge_tag(id, num_tagged); + } + FOREACH_MAIN_ID_END; - if (num_tagged[INDEX_ID_NULL] == 0) { - BKE_report(op->reports, RPT_INFO, "No orphanned data-blocks to purge"); - return OPERATOR_CANCELLED; - } - } + if (num_tagged[INDEX_ID_NULL] == 0) { + BKE_report(op->reports, RPT_INFO, "No orphanned data-blocks to purge"); + return OPERATOR_CANCELLED; + } + } - BKE_id_multi_tagged_delete(bmain); + BKE_id_multi_tagged_delete(bmain); - BKE_reportf(op->reports, RPT_INFO, "Deleted %d data-blocks", num_tagged[INDEX_ID_NULL]); + BKE_reportf(op->reports, RPT_INFO, "Deleted %d data-blocks", num_tagged[INDEX_ID_NULL]); - /* XXX: tree management normally happens from draw_outliner(), but when - * you're clicking to fast on Delete object from context menu in - * outliner several mouse events can be handled in one cycle without - * handling notifiers/redraw which leads to deleting the same object twice. - * cleanup tree here to prevent such cases. */ - outliner_cleanup_tree(soops); + /* XXX: tree management normally happens from draw_outliner(), but when + * you're clicking to fast on Delete object from context menu in + * outliner several mouse events can be handled in one cycle without + * handling notifiers/redraw which leads to deleting the same object twice. + * cleanup tree here to prevent such cases. */ + outliner_cleanup_tree(soops); - DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); - return OPERATOR_FINISHED; + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); + return OPERATOR_FINISHED; } void OUTLINER_OT_orphans_purge(wmOperatorType *ot) { - /* identifiers */ - ot->idname = "OUTLINER_OT_orphans_purge"; - ot->name = "Purge All"; - ot->description = "Clear all orphaned data-blocks without any users from the file"; + /* identifiers */ + ot->idname = "OUTLINER_OT_orphans_purge"; + ot->name = "Purge All"; + ot->description = "Clear all orphaned data-blocks without any users from the file"; - /* callbacks */ - ot->invoke = outliner_orphans_purge_invoke; - ot->exec = outliner_orphans_purge_exec; - ot->poll = ed_operator_outliner_id_orphans_active; + /* callbacks */ + ot->invoke = outliner_orphans_purge_invoke; + ot->exec = outliner_orphans_purge_exec; + ot->poll = ed_operator_outliner_id_orphans_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - PropertyRNA *prop = RNA_def_int(ot->srna, "num_deleted", 0, 0, INT_MAX, "", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + /* properties */ + PropertyRNA *prop = RNA_def_int(ot->srna, "num_deleted", 0, 0, INT_MAX, "", "", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 57fed22d36b..d382384076b 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -21,7 +21,6 @@ * \ingroup spoutliner */ - #ifndef __OUTLINER_INTERN_H__ #define __OUTLINER_INTERN_H__ @@ -46,73 +45,106 @@ struct wmKeyConfig; struct wmOperatorType; typedef enum TreeElementInsertType { - TE_INSERT_BEFORE, - TE_INSERT_AFTER, - TE_INSERT_INTO, + TE_INSERT_BEFORE, + TE_INSERT_AFTER, + TE_INSERT_INTO, } TreeElementInsertType; typedef enum TreeTraversalAction { - /* Continue traversal regularly, don't skip children. */ - TRAVERSE_CONTINUE = 0, - /* Stop traversal */ - TRAVERSE_BREAK, - /* Continue traversal, but skip childs of traversed element */ - TRAVERSE_SKIP_CHILDS, + /* Continue traversal regularly, don't skip children. */ + TRAVERSE_CONTINUE = 0, + /* Stop traversal */ + TRAVERSE_BREAK, + /* Continue traversal, but skip childs of traversed element */ + TRAVERSE_SKIP_CHILDS, } TreeTraversalAction; typedef TreeTraversalAction (*TreeTraversalFunc)(struct TreeElement *te, void *customdata); - typedef struct TreeElement { - struct TreeElement *next, *prev, *parent; - ListBase subtree; - int xs, ys; // do selection - TreeStoreElem *store_elem; // element in tree store - short flag; // flag for non-saved stuff - short index; // index for data arrays - short idcode; // from TreeStore id - short xend; // width of item display, for select - const char *name; - void *directdata; // Armature Bones, Base, Sequence, Strip... - PointerRNA rnaptr; // RNA Pointer + struct TreeElement *next, *prev, *parent; + ListBase subtree; + int xs, ys; // do selection + TreeStoreElem *store_elem; // element in tree store + short flag; // flag for non-saved stuff + short index; // index for data arrays + short idcode; // from TreeStore id + short xend; // width of item display, for select + const char *name; + void *directdata; // Armature Bones, Base, Sequence, Strip... + PointerRNA rnaptr; // RNA Pointer } TreeElement; typedef struct TreeElementIcon { - struct ID *drag_id, *drag_parent; - int icon; + struct ID *drag_id, *drag_parent; + int icon; } TreeElementIcon; #define TREESTORE_ID_TYPE(_id) \ - (ELEM(GS((_id)->name), ID_SCE, ID_LI, ID_OB, ID_ME, ID_CU, ID_MB, ID_NT, ID_MA, ID_TE, ID_IM, ID_LT, ID_LA, ID_CA) || \ - ELEM(GS((_id)->name), ID_KE, ID_WO, ID_SPK, ID_GR, ID_AR, ID_AC, ID_BR, ID_PA, ID_GD, ID_LS, ID_LP) || \ - /* Only in 'blendfile' mode ... :/ */ \ - ELEM(GS((_id)->name), ID_SCR, ID_WM, ID_TXT, ID_VF, ID_SO, ID_CF, ID_PAL, ID_MC, ID_WS, ID_MSK, ID_PC)) + (ELEM(GS((_id)->name), \ + ID_SCE, \ + ID_LI, \ + ID_OB, \ + ID_ME, \ + ID_CU, \ + ID_MB, \ + ID_NT, \ + ID_MA, \ + ID_TE, \ + ID_IM, \ + ID_LT, \ + ID_LA, \ + ID_CA) || \ + ELEM(GS((_id)->name), \ + ID_KE, \ + ID_WO, \ + ID_SPK, \ + ID_GR, \ + ID_AR, \ + ID_AC, \ + ID_BR, \ + ID_PA, \ + ID_GD, \ + ID_LS, \ + ID_LP) || /* Only in 'blendfile' mode ... :/ */ \ + ELEM(GS((_id)->name), \ + ID_SCR, \ + ID_WM, \ + ID_TXT, \ + ID_VF, \ + ID_SO, \ + ID_CF, \ + ID_PAL, \ + ID_MC, \ + ID_WS, \ + ID_MSK, \ + ID_PC)) /* TreeElement->flag */ enum { - TE_ACTIVE = (1 << 0), - /* Closed items display their children as icon within the row. TE_ICONROW is for - * these child-items that are visible but only within the row of the closed parent. */ - TE_ICONROW = (1 << 1), - TE_LAZY_CLOSED = (1 << 2), - TE_FREE_NAME = (1 << 3), - TE_DISABLED = (1 << 4), - TE_DRAGGING = (1 << 5), + TE_ACTIVE = (1 << 0), + /* Closed items display their children as icon within the row. TE_ICONROW is for + * these child-items that are visible but only within the row of the closed parent. */ + TE_ICONROW = (1 << 1), + TE_LAZY_CLOSED = (1 << 2), + TE_FREE_NAME = (1 << 3), + TE_DISABLED = (1 << 4), + TE_DRAGGING = (1 << 5), }; /* button events */ -#define OL_NAMEBUTTON 1 +#define OL_NAMEBUTTON 1 typedef enum { - OL_DRAWSEL_NONE = 0, /* inactive (regular black text) */ - OL_DRAWSEL_NORMAL = 1, /* active object (draws white text) */ - OL_DRAWSEL_ACTIVE = 2, /* active obdata (draws a circle around the icon) */ + OL_DRAWSEL_NONE = 0, /* inactive (regular black text) */ + OL_DRAWSEL_NORMAL = 1, /* active object (draws white text) */ + OL_DRAWSEL_ACTIVE = 2, /* active obdata (draws a circle around the icon) */ } eOLDrawState; typedef enum { - OL_SETSEL_NONE = 0, /* don't change the selection state */ - OL_SETSEL_NORMAL = 1, /* select the item */ - OL_SETSEL_EXTEND = 2, /* select the item and extend (also toggles selection) */ + OL_SETSEL_NONE = 0, /* don't change the selection state */ + OL_SETSEL_NORMAL = 1, /* select the item */ + OL_SETSEL_EXTEND = 2, /* select the item and extend (also toggles selection) */ } eOLSetState; /* get TreeStoreElem associated with a TreeElement @@ -124,14 +156,14 @@ typedef enum { #define OL_Y_OFFSET 2 #define OL_TOG_RESTRICT_SELECTX (UI_UNIT_X * 3.0f + V2D_SCROLL_WIDTH) -#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 2.0f + V2D_SCROLL_WIDTH) +#define OL_TOG_RESTRICT_VIEWX (UI_UNIT_X * 2.0f + V2D_SCROLL_WIDTH) #define OL_TOG_RESTRICT_RENDERX (UI_UNIT_X + V2D_SCROLL_WIDTH) #define OL_TOGW OL_TOG_RESTRICT_SELECTX -#define OL_RNA_COLX (UI_UNIT_X * 15) -#define OL_RNA_COL_SIZEX (UI_UNIT_X * 7.5f) -#define OL_RNA_COL_SPACEX (UI_UNIT_X * 2.5f) +#define OL_RNA_COLX (UI_UNIT_X * 15) +#define OL_RNA_COL_SIZEX (UI_UNIT_X * 7.5f) +#define OL_RNA_COL_SPACEX (UI_UNIT_X * 2.5f) /* The outliner display modes that support the filter system. * Note: keep it synced with space_outliner.py */ @@ -153,10 +185,11 @@ typedef enum { * - not searching into RNA items helps but isn't the complete solution */ -#define SEARCHING_OUTLINER(sov) (sov->search_flags & SO_SEARCH_RECURSIVE) +#define SEARCHING_OUTLINER(sov) (sov->search_flags & SO_SEARCH_RECURSIVE) /* is the current element open? if so we also show children */ -#define TSELEM_OPEN(telm, sv) ( (telm->flag & TSE_CLOSED) == 0 || (SEARCHING_OUTLINER(sv) && (telm->flag & TSE_CHILDSEARCH)) ) +#define TSELEM_OPEN(telm, sv) \ + ((telm->flag & TSE_CLOSED) == 0 || (SEARCHING_OUTLINER(sv) && (telm->flag & TSE_CHILDSEARCH))) /* outliner_tree.c ----------------------------------------------- */ @@ -164,13 +197,14 @@ void outliner_free_tree(ListBase *tree); void outliner_cleanup_tree(struct SpaceOutliner *soops); void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree); -void outliner_build_tree( - struct Main *mainvar, - struct Scene *scene, struct ViewLayer *view_layer, - struct SpaceOutliner *soops, struct ARegion *ar); +void outliner_build_tree(struct Main *mainvar, + struct Scene *scene, + struct ViewLayer *view_layer, + struct SpaceOutliner *soops, + struct ARegion *ar); typedef struct IDsSelectedData { - struct ListBase selected_array; + struct ListBase selected_array; } IDsSelectedData; TreeTraversalAction outliner_find_selected_collections(struct TreeElement *te, void *customdata); @@ -183,38 +217,62 @@ void draw_outliner(const struct bContext *C); TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te); /* outliner_select.c -------------------------------------------- */ -eOLDrawState tree_element_type_active( - struct bContext *C, struct Scene *scene, struct ViewLayer *view_layer, struct SpaceOutliner *soops, - TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive); -eOLDrawState tree_element_active(struct bContext *C, struct Scene *scene, struct ViewLayer *view_layer, SpaceOutliner *soops, - TreeElement *te, const eOLSetState set, const bool handle_all_types); +eOLDrawState tree_element_type_active(struct bContext *C, + struct Scene *scene, + struct ViewLayer *view_layer, + struct SpaceOutliner *soops, + TreeElement *te, + TreeStoreElem *tselem, + const eOLSetState set, + bool recursive); +eOLDrawState tree_element_active(struct bContext *C, + struct Scene *scene, + struct ViewLayer *view_layer, + SpaceOutliner *soops, + TreeElement *te, + const eOLSetState set, + const bool handle_all_types); void outliner_item_do_activate_from_tree_element( - struct bContext *C, TreeElement *te, TreeStoreElem *tselem, - bool extend, bool recursive); -int outliner_item_do_activate_from_cursor( - struct bContext *C, const int mval[2], - bool extend, bool recursive); - -void outliner_item_select( - struct SpaceOutliner *soops, const struct TreeElement *te, - const bool extend, const bool toggle); - -void outliner_object_mode_toggle( - struct bContext *C, Scene *scene, ViewLayer *view_layer, - Base *base); + struct bContext *C, TreeElement *te, TreeStoreElem *tselem, bool extend, bool recursive); +int outliner_item_do_activate_from_cursor(struct bContext *C, + const int mval[2], + bool extend, + bool recursive); + +void outliner_item_select(struct SpaceOutliner *soops, + const struct TreeElement *te, + const bool extend, + const bool toggle); + +void outliner_object_mode_toggle(struct bContext *C, + Scene *scene, + ViewLayer *view_layer, + Base *base); /* outliner_edit.c ---------------------------------------------- */ -typedef void (*outliner_operation_cb)( - struct bContext *C, struct ReportList *, struct Scene *scene, - struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *); - -void outliner_do_object_operation_ex( - struct bContext *C, struct ReportList *reports, struct Scene *scene, struct SpaceOutliner *soops, - struct ListBase *lb, outliner_operation_cb operation_cb, void *user_data, bool recurse_selected); -void outliner_do_object_operation( - struct bContext *C, struct ReportList *reports, struct Scene *scene, struct SpaceOutliner *soops, - struct ListBase *lb, outliner_operation_cb operation_cb); +typedef void (*outliner_operation_cb)(struct bContext *C, + struct ReportList *, + struct Scene *scene, + struct TreeElement *, + struct TreeStoreElem *, + TreeStoreElem *, + void *); + +void outliner_do_object_operation_ex(struct bContext *C, + struct ReportList *reports, + struct Scene *scene, + struct SpaceOutliner *soops, + struct ListBase *lb, + outliner_operation_cb operation_cb, + void *user_data, + bool recurse_selected); +void outliner_do_object_operation(struct bContext *C, + struct ReportList *reports, + struct Scene *scene, + struct SpaceOutliner *soops, + struct ListBase *lb, + outliner_operation_cb operation_cb); int common_restrict_check(struct bContext *C, struct Object *ob); @@ -222,29 +280,57 @@ int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel); bool outliner_flag_set(ListBase *lb, short flag, short set); bool outliner_flag_flip(ListBase *lb, short flag); -void item_rename_cb( - struct bContext *C, struct ReportList *reports, struct Scene *scene, - TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -void lib_relocate_cb( - struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te, - struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -void lib_reload_cb( - struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te, - struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); - -void id_delete_cb( - struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te, - struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -void id_remap_cb( - struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te, - struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); - -void item_object_mode_enter_cb( - struct bContext *C, struct ReportList *reports, struct Scene *scene, - TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -void item_object_mode_exit_cb( - struct bContext *C, struct ReportList *reports, struct Scene *scene, - TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); +void item_rename_cb(struct bContext *C, + struct ReportList *reports, + struct Scene *scene, + TreeElement *te, + struct TreeStoreElem *tsep, + struct TreeStoreElem *tselem, + void *user_data); +void lib_relocate_cb(struct bContext *C, + struct ReportList *reports, + struct Scene *scene, + struct TreeElement *te, + struct TreeStoreElem *tsep, + struct TreeStoreElem *tselem, + void *user_data); +void lib_reload_cb(struct bContext *C, + struct ReportList *reports, + struct Scene *scene, + struct TreeElement *te, + struct TreeStoreElem *tsep, + struct TreeStoreElem *tselem, + void *user_data); + +void id_delete_cb(struct bContext *C, + struct ReportList *reports, + struct Scene *scene, + struct TreeElement *te, + struct TreeStoreElem *tsep, + struct TreeStoreElem *tselem, + void *user_data); +void id_remap_cb(struct bContext *C, + struct ReportList *reports, + struct Scene *scene, + struct TreeElement *te, + struct TreeStoreElem *tsep, + struct TreeStoreElem *tselem, + void *user_data); + +void item_object_mode_enter_cb(struct bContext *C, + struct ReportList *reports, + struct Scene *scene, + TreeElement *te, + struct TreeStoreElem *tsep, + struct TreeStoreElem *tselem, + void *user_data); +void item_object_mode_exit_cb(struct bContext *C, + struct ReportList *reports, + struct Scene *scene, + TreeElement *te, + struct TreeStoreElem *tsep, + struct TreeStoreElem *tselem, + void *user_data); void outliner_set_coordinates(struct ARegion *ar, struct SpaceOutliner *soops); @@ -345,17 +431,26 @@ void OUTLINER_OT_unhide_all(struct wmOperatorType *ot); /* outliner_utils.c ---------------------------------------------- */ -TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops, const ListBase *tree, float view_co_y); -TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *soops, const TreeElement *parent_te, float view_co_x); +TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops, + const ListBase *tree, + float view_co_y); +TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *soops, + const TreeElement *parent_te, + float view_co_x); TreeElement *outliner_find_tse(struct SpaceOutliner *soops, const TreeStoreElem *tse); TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem); -TreeElement *outliner_find_parent_element(ListBase *lb, TreeElement *parent_te, const TreeElement *child_te); +TreeElement *outliner_find_parent_element(ListBase *lb, + TreeElement *parent_te, + const TreeElement *child_te); TreeElement *outliner_find_id(struct SpaceOutliner *soops, ListBase *lb, const struct ID *id); TreeElement *outliner_find_posechannel(ListBase *lb, const struct bPoseChannel *pchan); TreeElement *outliner_find_editbone(ListBase *lb, const struct EditBone *ebone); struct ID *outliner_search_back(SpaceOutliner *soops, TreeElement *te, short idcode); -bool outliner_tree_traverse(const SpaceOutliner *soops, ListBase *tree, int filter_te_flag, int filter_tselem_flag, - TreeTraversalFunc func, void *customdata); - +bool outliner_tree_traverse(const SpaceOutliner *soops, + ListBase *tree, + int filter_te_flag, + int filter_tselem_flag, + TreeTraversalFunc func, + void *customdata); #endif /* __OUTLINER_INTERN_H__ */ diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index c14a5eace91..f155a2d5f89 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -23,12 +23,10 @@ #include "MEM_guardedalloc.h" - #include "DNA_collection_types.h" #include "BLT_translation.h" - #include "GPU_immediate.h" #include "GPU_state.h" @@ -49,80 +47,80 @@ void outliner_operatortypes(void) { - WM_operatortype_append(OUTLINER_OT_highlight_update); - WM_operatortype_append(OUTLINER_OT_item_activate); - WM_operatortype_append(OUTLINER_OT_select_box); - WM_operatortype_append(OUTLINER_OT_item_openclose); - WM_operatortype_append(OUTLINER_OT_item_rename); - WM_operatortype_append(OUTLINER_OT_item_drag_drop); - WM_operatortype_append(OUTLINER_OT_operation); - WM_operatortype_append(OUTLINER_OT_scene_operation); - WM_operatortype_append(OUTLINER_OT_object_operation); - WM_operatortype_append(OUTLINER_OT_lib_operation); - WM_operatortype_append(OUTLINER_OT_lib_relocate); - WM_operatortype_append(OUTLINER_OT_id_operation); - WM_operatortype_append(OUTLINER_OT_id_delete); - WM_operatortype_append(OUTLINER_OT_id_remap); - WM_operatortype_append(OUTLINER_OT_id_copy); - WM_operatortype_append(OUTLINER_OT_id_paste); - WM_operatortype_append(OUTLINER_OT_data_operation); - WM_operatortype_append(OUTLINER_OT_animdata_operation); - WM_operatortype_append(OUTLINER_OT_action_set); - WM_operatortype_append(OUTLINER_OT_constraint_operation); - WM_operatortype_append(OUTLINER_OT_modifier_operation); - - WM_operatortype_append(OUTLINER_OT_show_one_level); - WM_operatortype_append(OUTLINER_OT_show_active); - WM_operatortype_append(OUTLINER_OT_show_hierarchy); - WM_operatortype_append(OUTLINER_OT_scroll_page); - - WM_operatortype_append(OUTLINER_OT_select_all); - WM_operatortype_append(OUTLINER_OT_expanded_toggle); - - WM_operatortype_append(OUTLINER_OT_keyingset_add_selected); - WM_operatortype_append(OUTLINER_OT_keyingset_remove_selected); - - WM_operatortype_append(OUTLINER_OT_drivers_add_selected); - WM_operatortype_append(OUTLINER_OT_drivers_delete_selected); - - WM_operatortype_append(OUTLINER_OT_orphans_purge); - - WM_operatortype_append(OUTLINER_OT_parent_drop); - WM_operatortype_append(OUTLINER_OT_parent_clear); - WM_operatortype_append(OUTLINER_OT_scene_drop); - WM_operatortype_append(OUTLINER_OT_material_drop); - WM_operatortype_append(OUTLINER_OT_collection_drop); - - /* collections */ - WM_operatortype_append(OUTLINER_OT_collection_new); - 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); - WM_operatortype_append(OUTLINER_OT_collection_link); - WM_operatortype_append(OUTLINER_OT_collection_instance); - WM_operatortype_append(OUTLINER_OT_collection_exclude_set); - WM_operatortype_append(OUTLINER_OT_collection_exclude_clear); - WM_operatortype_append(OUTLINER_OT_collection_holdout_set); - WM_operatortype_append(OUTLINER_OT_collection_holdout_clear); - WM_operatortype_append(OUTLINER_OT_collection_indirect_only_set); - WM_operatortype_append(OUTLINER_OT_collection_indirect_only_clear); - - WM_operatortype_append(OUTLINER_OT_collection_isolate); - WM_operatortype_append(OUTLINER_OT_collection_disable); - WM_operatortype_append(OUTLINER_OT_collection_enable); - WM_operatortype_append(OUTLINER_OT_collection_hide); - WM_operatortype_append(OUTLINER_OT_collection_show); - WM_operatortype_append(OUTLINER_OT_collection_disable_render); - WM_operatortype_append(OUTLINER_OT_collection_enable_render); - WM_operatortype_append(OUTLINER_OT_collection_hide_inside); - WM_operatortype_append(OUTLINER_OT_collection_show_inside); - WM_operatortype_append(OUTLINER_OT_hide); - WM_operatortype_append(OUTLINER_OT_unhide_all); + WM_operatortype_append(OUTLINER_OT_highlight_update); + WM_operatortype_append(OUTLINER_OT_item_activate); + WM_operatortype_append(OUTLINER_OT_select_box); + WM_operatortype_append(OUTLINER_OT_item_openclose); + WM_operatortype_append(OUTLINER_OT_item_rename); + WM_operatortype_append(OUTLINER_OT_item_drag_drop); + WM_operatortype_append(OUTLINER_OT_operation); + WM_operatortype_append(OUTLINER_OT_scene_operation); + WM_operatortype_append(OUTLINER_OT_object_operation); + WM_operatortype_append(OUTLINER_OT_lib_operation); + WM_operatortype_append(OUTLINER_OT_lib_relocate); + WM_operatortype_append(OUTLINER_OT_id_operation); + WM_operatortype_append(OUTLINER_OT_id_delete); + WM_operatortype_append(OUTLINER_OT_id_remap); + WM_operatortype_append(OUTLINER_OT_id_copy); + WM_operatortype_append(OUTLINER_OT_id_paste); + WM_operatortype_append(OUTLINER_OT_data_operation); + WM_operatortype_append(OUTLINER_OT_animdata_operation); + WM_operatortype_append(OUTLINER_OT_action_set); + WM_operatortype_append(OUTLINER_OT_constraint_operation); + WM_operatortype_append(OUTLINER_OT_modifier_operation); + + WM_operatortype_append(OUTLINER_OT_show_one_level); + WM_operatortype_append(OUTLINER_OT_show_active); + WM_operatortype_append(OUTLINER_OT_show_hierarchy); + WM_operatortype_append(OUTLINER_OT_scroll_page); + + WM_operatortype_append(OUTLINER_OT_select_all); + WM_operatortype_append(OUTLINER_OT_expanded_toggle); + + WM_operatortype_append(OUTLINER_OT_keyingset_add_selected); + WM_operatortype_append(OUTLINER_OT_keyingset_remove_selected); + + WM_operatortype_append(OUTLINER_OT_drivers_add_selected); + WM_operatortype_append(OUTLINER_OT_drivers_delete_selected); + + WM_operatortype_append(OUTLINER_OT_orphans_purge); + + WM_operatortype_append(OUTLINER_OT_parent_drop); + WM_operatortype_append(OUTLINER_OT_parent_clear); + WM_operatortype_append(OUTLINER_OT_scene_drop); + WM_operatortype_append(OUTLINER_OT_material_drop); + WM_operatortype_append(OUTLINER_OT_collection_drop); + + /* collections */ + WM_operatortype_append(OUTLINER_OT_collection_new); + 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); + WM_operatortype_append(OUTLINER_OT_collection_link); + WM_operatortype_append(OUTLINER_OT_collection_instance); + WM_operatortype_append(OUTLINER_OT_collection_exclude_set); + WM_operatortype_append(OUTLINER_OT_collection_exclude_clear); + WM_operatortype_append(OUTLINER_OT_collection_holdout_set); + WM_operatortype_append(OUTLINER_OT_collection_holdout_clear); + WM_operatortype_append(OUTLINER_OT_collection_indirect_only_set); + WM_operatortype_append(OUTLINER_OT_collection_indirect_only_clear); + + WM_operatortype_append(OUTLINER_OT_collection_isolate); + WM_operatortype_append(OUTLINER_OT_collection_disable); + WM_operatortype_append(OUTLINER_OT_collection_enable); + WM_operatortype_append(OUTLINER_OT_collection_hide); + WM_operatortype_append(OUTLINER_OT_collection_show); + WM_operatortype_append(OUTLINER_OT_collection_disable_render); + WM_operatortype_append(OUTLINER_OT_collection_enable_render); + WM_operatortype_append(OUTLINER_OT_collection_hide_inside); + WM_operatortype_append(OUTLINER_OT_collection_show_inside); + WM_operatortype_append(OUTLINER_OT_hide); + WM_operatortype_append(OUTLINER_OT_unhide_all); } void outliner_keymap(wmKeyConfig *keyconf) { - WM_keymap_ensure(keyconf, "Outliner", SPACE_OUTLINER, 0); + WM_keymap_ensure(keyconf, "Outliner", SPACE_OUTLINER, 0); } diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 9866b43a6a6..bab5ee02916 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -63,7 +63,6 @@ #include "WM_api.h" #include "WM_types.h" - #include "UI_interface.h" #include "UI_view2d.h" @@ -72,38 +71,36 @@ #include "outliner_intern.h" -static bool do_outliner_activate_common( - bContext *C, - Main *bmain, - Depsgraph *depsgraph, - Scene *scene, - ViewLayer *view_layer, - Base *base, - const bool extend, - const bool do_exit) +static bool do_outliner_activate_common(bContext *C, + Main *bmain, + Depsgraph *depsgraph, + Scene *scene, + ViewLayer *view_layer, + Base *base, + const bool extend, + const bool do_exit) { - bool use_all = false; - - if (do_exit) { - FOREACH_OBJECT_BEGIN(view_layer, ob_iter) - { - ED_object_mode_generic_exit(bmain, depsgraph, scene, ob_iter); - } - FOREACH_OBJECT_END; - } - - /* Just like clicking in the object changes the active object, - * clicking on the object data should change it as well. */ - ED_object_base_activate(C, base); - - if (extend) { - use_all = true; - } - else { - ED_object_base_deselect_all(view_layer, NULL, SEL_DESELECT); - } - - return use_all; + bool use_all = false; + + if (do_exit) { + FOREACH_OBJECT_BEGIN (view_layer, ob_iter) { + ED_object_mode_generic_exit(bmain, depsgraph, scene, ob_iter); + } + FOREACH_OBJECT_END; + } + + /* Just like clicking in the object changes the active object, + * clicking on the object data should change it as well. */ + ED_object_base_activate(C, base); + + if (extend) { + use_all = true; + } + else { + ED_object_base_deselect_all(view_layer, NULL, SEL_DESELECT); + } + + return use_all; } /** @@ -112,142 +109,145 @@ static bool do_outliner_activate_common( * If extend is used, we try to have the other compatible selected objects in the new mode as well. * Otherwise only the new object will be active, selected and in the edit mode. */ -static void do_outliner_activate_obdata(bContext *C, Scene *scene, ViewLayer *view_layer, Base *base, const bool extend) +static void do_outliner_activate_obdata( + bContext *C, Scene *scene, ViewLayer *view_layer, Base *base, const bool extend) { - Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Object *obact = OBACT(view_layer); - Object *ob = base->object; - bool use_all = false; - - if (obact == NULL) { - ED_object_base_activate(C, base); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - obact = ob; - use_all = true; - } - else if (obact->data == ob->data) { - use_all = true; - } - else if (obact->mode == OB_MODE_OBJECT) { - use_all = do_outliner_activate_common(C, bmain, depsgraph, scene, view_layer, base, extend, false); - } - else if ((ob->type != obact->type) || - ((obact->mode & OB_MODE_EDIT) == 0) || - ((obact->mode & OB_MODE_POSE) && ELEM(OB_ARMATURE, ob->type, obact->type)) || - !extend) - { - use_all = do_outliner_activate_common(C, bmain, depsgraph, scene, view_layer, base, extend, true); - } - - if (use_all) { - WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); - } - else { - bool ok; - if (BKE_object_is_in_editmode(ob)) { - ok = ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA); - } - else { - ok = ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_NO_CONTEXT); - } - if (ok) { - ED_object_base_select(base, (ob->mode & OB_MODE_EDIT) ? BA_SELECT : BA_DESELECT); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } - } + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Object *obact = OBACT(view_layer); + Object *ob = base->object; + bool use_all = false; + + if (obact == NULL) { + ED_object_base_activate(C, base); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + obact = ob; + use_all = true; + } + else if (obact->data == ob->data) { + use_all = true; + } + else if (obact->mode == OB_MODE_OBJECT) { + use_all = do_outliner_activate_common( + C, bmain, depsgraph, scene, view_layer, base, extend, false); + } + else if ((ob->type != obact->type) || ((obact->mode & OB_MODE_EDIT) == 0) || + ((obact->mode & OB_MODE_POSE) && ELEM(OB_ARMATURE, ob->type, obact->type)) || !extend) { + use_all = do_outliner_activate_common( + C, bmain, depsgraph, scene, view_layer, base, extend, true); + } + + if (use_all) { + WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); + } + else { + bool ok; + if (BKE_object_is_in_editmode(ob)) { + ok = ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA); + } + else { + ok = ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_NO_CONTEXT); + } + if (ok) { + ED_object_base_select(base, (ob->mode & OB_MODE_EDIT) ? BA_SELECT : BA_DESELECT); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + } + } } -static void do_outliner_activate_pose(bContext *C, Scene *scene, ViewLayer *view_layer, Base *base, const bool extend) +static void do_outliner_activate_pose( + bContext *C, Scene *scene, ViewLayer *view_layer, Base *base, const bool extend) { - Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - Object *obact = OBACT(view_layer); - Object *ob = base->object; - bool use_all = false; - - if (obact == NULL) { - ED_object_base_activate(C, base); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - obact = ob; - use_all = true; - } - else if (obact->data == ob->data) { - use_all = true; - } - else if (obact->mode == OB_MODE_OBJECT) { - use_all = do_outliner_activate_common(C, bmain, depsgraph, scene, view_layer, base, extend, false); - } - else if ((!ELEM(ob->type, obact->type)) || - ((obact->mode & OB_MODE_EDIT) && ELEM(OB_ARMATURE, ob->type, obact->type))) - { - use_all = do_outliner_activate_common(C, bmain, depsgraph, scene, view_layer, base, extend, true); - } - - if (use_all) { - WM_operator_name_call(C, "OBJECT_OT_posemode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); - } - else { - bool ok = false; - if (ob->mode & OB_MODE_POSE) { - ok = ED_object_posemode_exit_ex(bmain, ob); - } - else { - ok = ED_object_posemode_enter_ex(bmain, ob); - } - if (ok) { - ED_object_base_select(base, (ob->mode & OB_MODE_POSE) ? BA_SELECT : BA_DESELECT); - - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } - } + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + Object *obact = OBACT(view_layer); + Object *ob = base->object; + bool use_all = false; + + if (obact == NULL) { + ED_object_base_activate(C, base); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + obact = ob; + use_all = true; + } + else if (obact->data == ob->data) { + use_all = true; + } + else if (obact->mode == OB_MODE_OBJECT) { + use_all = do_outliner_activate_common( + C, bmain, depsgraph, scene, view_layer, base, extend, false); + } + else if ((!ELEM(ob->type, obact->type)) || + ((obact->mode & OB_MODE_EDIT) && ELEM(OB_ARMATURE, ob->type, obact->type))) { + use_all = do_outliner_activate_common( + C, bmain, depsgraph, scene, view_layer, base, extend, true); + } + + if (use_all) { + WM_operator_name_call(C, "OBJECT_OT_posemode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); + } + else { + bool ok = false; + if (ob->mode & OB_MODE_POSE) { + ok = ED_object_posemode_exit_ex(bmain, ob); + } + else { + ok = ED_object_posemode_enter_ex(bmain, ob); + } + if (ok) { + ED_object_base_select(base, (ob->mode & OB_MODE_POSE) ? BA_SELECT : BA_DESELECT); + + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + } + } } /* For draw callback to run mode switching */ -void outliner_object_mode_toggle( - bContext *C, Scene *scene, ViewLayer *view_layer, - Base *base) +void outliner_object_mode_toggle(bContext *C, Scene *scene, ViewLayer *view_layer, Base *base) { - Object *obact = OBACT(view_layer); - if (obact->mode & OB_MODE_EDIT) { - do_outliner_activate_obdata(C, scene, view_layer, base, true); - } - else if (obact->mode & OB_MODE_POSE) { - do_outliner_activate_pose(C, scene, view_layer, base, true); - } + Object *obact = OBACT(view_layer); + if (obact->mode & OB_MODE_EDIT) { + do_outliner_activate_obdata(C, scene, view_layer, base, true); + } + else if (obact->mode & OB_MODE_POSE) { + do_outliner_activate_pose(C, scene, view_layer, base, true); + } } /* ****************************************************** */ /* Outliner Element Selection/Activation on Click */ -static eOLDrawState active_viewlayer( - bContext *C, Scene *UNUSED(scene), ViewLayer *UNUSED(sl), TreeElement *te, const eOLSetState set) +static eOLDrawState active_viewlayer(bContext *C, + Scene *UNUSED(scene), + ViewLayer *UNUSED(sl), + TreeElement *te, + const eOLSetState set) { - /* paranoia check */ - if (te->idcode != ID_SCE) { - return OL_DRAWSEL_NONE; - } - - ViewLayer *view_layer = te->directdata; - - if (set != OL_SETSEL_NONE) { - wmWindow *win = CTX_wm_window(C); - Scene *scene = WM_window_get_active_scene(win); - - if (BLI_findindex(&scene->view_layers, view_layer) != -1) { - WM_window_set_active_view_layer(win, view_layer); - WM_event_add_notifier(C, NC_SCREEN | ND_LAYER, NULL); - } - } - else { - return CTX_data_view_layer(C) == view_layer; - } - return OL_DRAWSEL_NONE; + /* paranoia check */ + if (te->idcode != ID_SCE) { + return OL_DRAWSEL_NONE; + } + + ViewLayer *view_layer = te->directdata; + + if (set != OL_SETSEL_NONE) { + wmWindow *win = CTX_wm_window(C); + Scene *scene = WM_window_get_active_scene(win); + + if (BLI_findindex(&scene->view_layers, view_layer) != -1) { + WM_window_set_active_view_layer(win, view_layer); + WM_event_add_notifier(C, NC_SCREEN | ND_LAYER, NULL); + } + } + else { + return CTX_data_view_layer(C) == view_layer; + } + return OL_DRAWSEL_NONE; } /** @@ -255,772 +255,856 @@ static eOLDrawState active_viewlayer( * CTRL+LMB: Select/Deselect object and all children. * CTRL+SHIFT+LMB: Add/Remove object and all children. */ -static void do_outliner_object_select_recursive(ViewLayer *view_layer, Object *ob_parent, bool select) +static void do_outliner_object_select_recursive(ViewLayer *view_layer, + Object *ob_parent, + bool select) { - Base *base; - - for (base = FIRSTBASE(view_layer); base; base = base->next) { - Object *ob = base->object; - if ((((base->flag & BASE_VISIBLE) != 0) && BKE_object_is_child_recursive(ob_parent, ob))) { - ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); - } - } + Base *base; + + for (base = FIRSTBASE(view_layer); base; base = base->next) { + Object *ob = base->object; + if ((((base->flag & BASE_VISIBLE) != 0) && BKE_object_is_child_recursive(ob_parent, ob))) { + ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); + } + } } static void do_outliner_bone_select_recursive(bArmature *arm, Bone *bone_parent, bool select) { - Bone *bone; - for (bone = bone_parent->childbase.first; bone; bone = bone->next) { - if (select && PBONE_SELECTABLE(arm, bone)) { - bone->flag |= BONE_SELECTED; - } - else { - bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); - } - do_outliner_bone_select_recursive(arm, bone, select); - } + Bone *bone; + for (bone = bone_parent->childbase.first; bone; bone = bone->next) { + if (select && PBONE_SELECTABLE(arm, bone)) { + bone->flag |= BONE_SELECTED; + } + else { + bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + } + do_outliner_bone_select_recursive(arm, bone, select); + } } static void do_outliner_ebone_select_recursive(bArmature *arm, EditBone *ebone_parent, bool select) { - EditBone *ebone; - for (ebone = ebone_parent->next; ebone; ebone = ebone->next) { - if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) { - if (select && EBONE_SELECTABLE(arm, ebone)) { - ebone->flag |= BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL; - } - else { - ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); - } - } - } + EditBone *ebone; + for (ebone = ebone_parent->next; ebone; ebone = ebone->next) { + if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) { + if (select && EBONE_SELECTABLE(arm, ebone)) { + ebone->flag |= BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL; + } + else { + ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + } + } + } } -static eOLDrawState tree_element_set_active_object( - bContext *C, Scene *scene, ViewLayer *view_layer, SpaceOutliner *soops, - TreeElement *te, const eOLSetState set, bool recursive) +static eOLDrawState tree_element_set_active_object(bContext *C, + Scene *scene, + ViewLayer *view_layer, + SpaceOutliner *soops, + TreeElement *te, + const eOLSetState set, + bool recursive) { - TreeStoreElem *tselem = TREESTORE(te); - Scene *sce; - Base *base; - Object *ob = NULL; - - /* if id is not object, we search back */ - if (te->idcode == ID_OB) { - ob = (Object *)tselem->id; - } - else { - ob = (Object *)outliner_search_back(soops, te, ID_OB); - if (ob == OBACT(view_layer)) { - return OL_DRAWSEL_NONE; - } - } - if (ob == NULL) { - return OL_DRAWSEL_NONE; - } - - sce = (Scene *)outliner_search_back(soops, te, ID_SCE); - if (sce && scene != sce) { - WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), sce); - scene = sce; - } - - /* find associated base in current scene */ - base = BKE_view_layer_base_find(view_layer, ob); - - if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) { - if (base != NULL) { - Object *obact = OBACT(view_layer); - const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT; - if (base && !BKE_object_is_mode_compat(base->object, object_mode)) { - if (object_mode == OB_MODE_OBJECT) { - struct Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_depsgraph(C); - ED_object_mode_generic_exit(bmain, depsgraph, scene, base->object); - } - if (!BKE_object_is_mode_compat(base->object, object_mode)) { - base = NULL; - } - } - } - } - - if (base) { - if (set == OL_SETSEL_EXTEND) { - /* swap select */ - if (base->flag & BASE_SELECTED) { - ED_object_base_select(base, BA_DESELECT); - } - else { - ED_object_base_select(base, BA_SELECT); - } - } - else { - /* deleselect all */ - - /* Only in object mode so we can switch the active object, - * keeping all objects in the current 'mode' selected, useful for multi-pose/edit mode. - * This keeps the convention that all objects in the current mode are also selected. - * see T55246. */ - if ((scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) ? (ob->mode == OB_MODE_OBJECT) : true) { - BKE_view_layer_base_deselect_all(view_layer); - } - ED_object_base_select(base, BA_SELECT); - } - - if (recursive) { - /* Recursive select/deselect for Object hierarchies */ - do_outliner_object_select_recursive(view_layer, ob, (base->flag & BASE_SELECTED) != 0); - } - - if (set != OL_SETSEL_NONE) { - ED_object_base_activate(C, base); /* adds notifier */ - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } - - if (ob != OBEDIT_FROM_VIEW_LAYER(view_layer)) { - ED_object_editmode_exit(C, EM_FREEDATA); - } - } - return OL_DRAWSEL_NORMAL; + TreeStoreElem *tselem = TREESTORE(te); + Scene *sce; + Base *base; + Object *ob = NULL; + + /* if id is not object, we search back */ + if (te->idcode == ID_OB) { + ob = (Object *)tselem->id; + } + else { + ob = (Object *)outliner_search_back(soops, te, ID_OB); + if (ob == OBACT(view_layer)) { + return OL_DRAWSEL_NONE; + } + } + if (ob == NULL) { + return OL_DRAWSEL_NONE; + } + + sce = (Scene *)outliner_search_back(soops, te, ID_SCE); + if (sce && scene != sce) { + WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), sce); + scene = sce; + } + + /* find associated base in current scene */ + base = BKE_view_layer_base_find(view_layer, ob); + + if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) { + if (base != NULL) { + Object *obact = OBACT(view_layer); + const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT; + if (base && !BKE_object_is_mode_compat(base->object, object_mode)) { + if (object_mode == OB_MODE_OBJECT) { + struct Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_depsgraph(C); + ED_object_mode_generic_exit(bmain, depsgraph, scene, base->object); + } + if (!BKE_object_is_mode_compat(base->object, object_mode)) { + base = NULL; + } + } + } + } + + if (base) { + if (set == OL_SETSEL_EXTEND) { + /* swap select */ + if (base->flag & BASE_SELECTED) { + ED_object_base_select(base, BA_DESELECT); + } + else { + ED_object_base_select(base, BA_SELECT); + } + } + else { + /* deleselect all */ + + /* Only in object mode so we can switch the active object, + * keeping all objects in the current 'mode' selected, useful for multi-pose/edit mode. + * This keeps the convention that all objects in the current mode are also selected. + * see T55246. */ + if ((scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) ? + (ob->mode == OB_MODE_OBJECT) : + true) { + BKE_view_layer_base_deselect_all(view_layer); + } + ED_object_base_select(base, BA_SELECT); + } + + if (recursive) { + /* Recursive select/deselect for Object hierarchies */ + do_outliner_object_select_recursive(view_layer, ob, (base->flag & BASE_SELECTED) != 0); + } + + if (set != OL_SETSEL_NONE) { + ED_object_base_activate(C, base); /* adds notifier */ + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + } + + if (ob != OBEDIT_FROM_VIEW_LAYER(view_layer)) { + ED_object_editmode_exit(C, EM_FREEDATA); + } + } + return OL_DRAWSEL_NORMAL; } -static eOLDrawState tree_element_active_material( - bContext *C, Scene *UNUSED(scene), ViewLayer *view_layer, SpaceOutliner *soops, - TreeElement *te, const eOLSetState set) +static eOLDrawState tree_element_active_material(bContext *C, + Scene *UNUSED(scene), + ViewLayer *view_layer, + SpaceOutliner *soops, + TreeElement *te, + const eOLSetState set) { - TreeElement *tes; - Object *ob; - - /* we search for the object parent */ - ob = (Object *)outliner_search_back(soops, te, ID_OB); - // note: ob->matbits can be NULL when a local object points to a library mesh. - if (ob == NULL || ob != OBACT(view_layer) || ob->matbits == NULL) { - return OL_DRAWSEL_NONE; /* just paranoia */ - } - - /* searching in ob mat array? */ - tes = te->parent; - if (tes->idcode == ID_OB) { - if (set != OL_SETSEL_NONE) { - ob->actcol = te->index + 1; - ob->matbits[te->index] = 1; // make ob material active too - } - else { - if (ob->actcol == te->index + 1) { - if (ob->matbits[te->index]) { - return OL_DRAWSEL_NORMAL; - } - } - } - } - /* or we search for obdata material */ - else { - if (set != OL_SETSEL_NONE) { - ob->actcol = te->index + 1; - ob->matbits[te->index] = 0; // make obdata material active too - } - else { - if (ob->actcol == te->index + 1) { - if (ob->matbits[te->index] == 0) { - return OL_DRAWSEL_NORMAL; - } - } - } - } - if (set != OL_SETSEL_NONE) { - /* Tagging object for update seems a bit stupid here, but looks like we have to do it - * for render views to update. See T42973. - * Note that RNA material update does it too, see e.g. rna_MaterialSlot_update(). */ - DEG_id_tag_update((ID *)ob, ID_RECALC_TRANSFORM); - WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL); - } - return OL_DRAWSEL_NONE; + TreeElement *tes; + Object *ob; + + /* we search for the object parent */ + ob = (Object *)outliner_search_back(soops, te, ID_OB); + // note: ob->matbits can be NULL when a local object points to a library mesh. + if (ob == NULL || ob != OBACT(view_layer) || ob->matbits == NULL) { + return OL_DRAWSEL_NONE; /* just paranoia */ + } + + /* searching in ob mat array? */ + tes = te->parent; + if (tes->idcode == ID_OB) { + if (set != OL_SETSEL_NONE) { + ob->actcol = te->index + 1; + ob->matbits[te->index] = 1; // make ob material active too + } + else { + if (ob->actcol == te->index + 1) { + if (ob->matbits[te->index]) { + return OL_DRAWSEL_NORMAL; + } + } + } + } + /* or we search for obdata material */ + else { + if (set != OL_SETSEL_NONE) { + ob->actcol = te->index + 1; + ob->matbits[te->index] = 0; // make obdata material active too + } + else { + if (ob->actcol == te->index + 1) { + if (ob->matbits[te->index] == 0) { + return OL_DRAWSEL_NORMAL; + } + } + } + } + if (set != OL_SETSEL_NONE) { + /* Tagging object for update seems a bit stupid here, but looks like we have to do it + * for render views to update. See T42973. + * Note that RNA material update does it too, see e.g. rna_MaterialSlot_update(). */ + DEG_id_tag_update((ID *)ob, ID_RECALC_TRANSFORM); + WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL); + } + return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_light( - bContext *UNUSED(C), Scene *UNUSED(scene), ViewLayer *view_layer, SpaceOutliner *soops, - TreeElement *te, const eOLSetState set) +static eOLDrawState tree_element_active_light(bContext *UNUSED(C), + Scene *UNUSED(scene), + ViewLayer *view_layer, + SpaceOutliner *soops, + TreeElement *te, + const eOLSetState set) { - Object *ob; - - /* we search for the object parent */ - ob = (Object *)outliner_search_back(soops, te, ID_OB); - if (ob == NULL || ob != OBACT(view_layer)) { - /* just paranoia */ - return OL_DRAWSEL_NONE; - } - - if (set != OL_SETSEL_NONE) { -// XXX extern_set_butspace(F5KEY, 0); - } - else { - return OL_DRAWSEL_NORMAL; - } - - return OL_DRAWSEL_NONE; + Object *ob; + + /* we search for the object parent */ + ob = (Object *)outliner_search_back(soops, te, ID_OB); + if (ob == NULL || ob != OBACT(view_layer)) { + /* just paranoia */ + return OL_DRAWSEL_NONE; + } + + if (set != OL_SETSEL_NONE) { + // XXX extern_set_butspace(F5KEY, 0); + } + else { + return OL_DRAWSEL_NORMAL; + } + + return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_camera( - bContext *UNUSED(C), Scene *scene, ViewLayer *UNUSED(sl), SpaceOutliner *soops, - TreeElement *te, const eOLSetState set) +static eOLDrawState tree_element_active_camera(bContext *UNUSED(C), + Scene *scene, + ViewLayer *UNUSED(sl), + SpaceOutliner *soops, + TreeElement *te, + const eOLSetState set) { - Object *ob = (Object *)outliner_search_back(soops, te, ID_OB); + Object *ob = (Object *)outliner_search_back(soops, te, ID_OB); - if (set != OL_SETSEL_NONE) { - return OL_DRAWSEL_NONE; - } + if (set != OL_SETSEL_NONE) { + return OL_DRAWSEL_NONE; + } - return scene->camera == ob; + return scene->camera == ob; } -static eOLDrawState tree_element_active_world( - bContext *C, Scene *scene, ViewLayer *UNUSED(sl), SpaceOutliner *UNUSED(soops), - TreeElement *te, const eOLSetState set) +static eOLDrawState tree_element_active_world(bContext *C, + Scene *scene, + ViewLayer *UNUSED(sl), + SpaceOutliner *UNUSED(soops), + TreeElement *te, + const eOLSetState set) { - TreeElement *tep; - TreeStoreElem *tselem = NULL; - Scene *sce = NULL; - - tep = te->parent; - if (tep) { - tselem = TREESTORE(tep); - if (tselem->type == 0) { - sce = (Scene *)tselem->id; - } - } - - if (set != OL_SETSEL_NONE) { - /* make new scene active */ - if (sce && scene != sce) { - WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), sce); - } - } - - if (tep == NULL || tselem->id == (ID *)scene) { - if (set != OL_SETSEL_NONE) { -// XXX extern_set_butspace(F8KEY, 0); - } - else { - return OL_DRAWSEL_NORMAL; - } - } - return OL_DRAWSEL_NONE; + TreeElement *tep; + TreeStoreElem *tselem = NULL; + Scene *sce = NULL; + + tep = te->parent; + if (tep) { + tselem = TREESTORE(tep); + if (tselem->type == 0) { + sce = (Scene *)tselem->id; + } + } + + if (set != OL_SETSEL_NONE) { + /* make new scene active */ + if (sce && scene != sce) { + WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), sce); + } + } + + if (tep == NULL || tselem->id == (ID *)scene) { + if (set != OL_SETSEL_NONE) { + // XXX extern_set_butspace(F8KEY, 0); + } + else { + return OL_DRAWSEL_NORMAL; + } + } + return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_defgroup( - bContext *C, ViewLayer *view_layer, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) +static eOLDrawState tree_element_active_defgroup(bContext *C, + ViewLayer *view_layer, + TreeElement *te, + TreeStoreElem *tselem, + const eOLSetState set) { - Object *ob; - - /* id in tselem is object */ - ob = (Object *)tselem->id; - if (set != OL_SETSEL_NONE) { - BLI_assert(te->index + 1 >= 0); - ob->actdef = te->index + 1; - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob); - } - else { - if (ob == OBACT(view_layer)) - if (ob->actdef == te->index + 1) { - return OL_DRAWSEL_NORMAL; - } - } - return OL_DRAWSEL_NONE; + Object *ob; + + /* id in tselem is object */ + ob = (Object *)tselem->id; + if (set != OL_SETSEL_NONE) { + BLI_assert(te->index + 1 >= 0); + ob->actdef = te->index + 1; + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob); + } + else { + if (ob == OBACT(view_layer)) + if (ob->actdef == te->index + 1) { + return OL_DRAWSEL_NORMAL; + } + } + return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_gplayer( - bContext *C, Scene *UNUSED(scene), TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) +static eOLDrawState tree_element_active_gplayer(bContext *C, + Scene *UNUSED(scene), + TreeElement *te, + TreeStoreElem *tselem, + const eOLSetState set) { - bGPdata *gpd = (bGPdata *)tselem->id; - bGPDlayer *gpl = te->directdata; - - /* We can only have a single "active" layer at a time - * and there must always be an active layer... - */ - if (set != OL_SETSEL_NONE) { - if (gpl) { - BKE_gpencil_layer_setactive(gpd, gpl); - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, gpd); - } - } - else { - return OL_DRAWSEL_NORMAL; - } - - return OL_DRAWSEL_NONE; + bGPdata *gpd = (bGPdata *)tselem->id; + bGPDlayer *gpl = te->directdata; + + /* We can only have a single "active" layer at a time + * and there must always be an active layer... + */ + if (set != OL_SETSEL_NONE) { + if (gpl) { + BKE_gpencil_layer_setactive(gpd, gpl); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, gpd); + } + } + else { + return OL_DRAWSEL_NORMAL; + } + + return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_posegroup( - bContext *C, Scene *UNUSED(scene), ViewLayer *view_layer, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set) +static eOLDrawState tree_element_active_posegroup(bContext *C, + Scene *UNUSED(scene), + ViewLayer *view_layer, + TreeElement *te, + TreeStoreElem *tselem, + const eOLSetState set) { - Object *ob = (Object *)tselem->id; - - if (set != OL_SETSEL_NONE) { - if (ob->pose) { - ob->pose->active_group = te->index + 1; - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - } - } - else { - if (ob == OBACT(view_layer) && ob->pose) { - if (ob->pose->active_group == te->index + 1) { - return OL_DRAWSEL_NORMAL; - } - } - } - return OL_DRAWSEL_NONE; + Object *ob = (Object *)tselem->id; + + if (set != OL_SETSEL_NONE) { + if (ob->pose) { + ob->pose->active_group = te->index + 1; + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + } + } + else { + if (ob == OBACT(view_layer) && ob->pose) { + if (ob->pose->active_group == te->index + 1) { + return OL_DRAWSEL_NORMAL; + } + } + } + return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_posechannel( - bContext *C, Scene *UNUSED(scene), ViewLayer *view_layer, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive) +static eOLDrawState tree_element_active_posechannel(bContext *C, + Scene *UNUSED(scene), + ViewLayer *view_layer, + TreeElement *te, + TreeStoreElem *tselem, + const eOLSetState set, + bool recursive) { - Object *ob = (Object *)tselem->id; - bArmature *arm = ob->data; - bPoseChannel *pchan = te->directdata; - - if (set != OL_SETSEL_NONE) { - if (!(pchan->bone->flag & BONE_HIDDEN_P)) { - - if (set != OL_SETSEL_EXTEND) { - /* Single select forces all other bones to get unselected. */ - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data(view_layer, NULL, &objects_len, OB_MODE_POSE); - for (uint object_index = 0; object_index < objects_len; object_index++) { - Object *ob_iter = BKE_object_pose_armature_get(objects[object_index]); - - /* Sanity checks. */ - if (ELEM(NULL, ob_iter, ob_iter->pose, ob_iter->data)) { - continue; - } - - bPoseChannel *pchannel; - for (pchannel = ob_iter->pose->chanbase.first; pchannel; pchannel = pchannel->next) { - pchannel->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); - } - - if (ob != ob_iter) { - DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); - } - } - MEM_freeN(objects); - } - - if ((set == OL_SETSEL_EXTEND) && (pchan->bone->flag & BONE_SELECTED)) { - pchan->bone->flag &= ~BONE_SELECTED; - } - else { - pchan->bone->flag |= BONE_SELECTED; - arm->act_bone = pchan->bone; - } - - if (recursive) { - /* Recursive select/deselect */ - do_outliner_bone_select_recursive(arm, pchan->bone, (pchan->bone->flag & BONE_SELECTED) != 0); - } - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, ob); - DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); - } - } - else { - if (ob == OBACT(view_layer) && ob->pose) { - if (pchan->bone->flag & BONE_SELECTED) { - return OL_DRAWSEL_NORMAL; - } - } - } - return OL_DRAWSEL_NONE; + Object *ob = (Object *)tselem->id; + bArmature *arm = ob->data; + bPoseChannel *pchan = te->directdata; + + if (set != OL_SETSEL_NONE) { + if (!(pchan->bone->flag & BONE_HIDDEN_P)) { + + if (set != OL_SETSEL_EXTEND) { + /* Single select forces all other bones to get unselected. */ + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_mode_unique_data( + view_layer, NULL, &objects_len, OB_MODE_POSE); + for (uint object_index = 0; object_index < objects_len; object_index++) { + Object *ob_iter = BKE_object_pose_armature_get(objects[object_index]); + + /* Sanity checks. */ + if (ELEM(NULL, ob_iter, ob_iter->pose, ob_iter->data)) { + continue; + } + + bPoseChannel *pchannel; + for (pchannel = ob_iter->pose->chanbase.first; pchannel; pchannel = pchannel->next) { + pchannel->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + } + + if (ob != ob_iter) { + DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); + } + } + MEM_freeN(objects); + } + + if ((set == OL_SETSEL_EXTEND) && (pchan->bone->flag & BONE_SELECTED)) { + pchan->bone->flag &= ~BONE_SELECTED; + } + else { + pchan->bone->flag |= BONE_SELECTED; + arm->act_bone = pchan->bone; + } + + if (recursive) { + /* Recursive select/deselect */ + do_outliner_bone_select_recursive( + arm, pchan->bone, (pchan->bone->flag & BONE_SELECTED) != 0); + } + + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, ob); + DEG_id_tag_update(&arm->id, ID_RECALC_SELECT); + } + } + else { + if (ob == OBACT(view_layer) && ob->pose) { + if (pchan->bone->flag & BONE_SELECTED) { + return OL_DRAWSEL_NORMAL; + } + } + } + return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_bone( - bContext *C, ViewLayer *view_layer, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive) +static eOLDrawState tree_element_active_bone(bContext *C, + ViewLayer *view_layer, + TreeElement *te, + TreeStoreElem *tselem, + const eOLSetState set, + bool recursive) { - bArmature *arm = (bArmature *)tselem->id; - Bone *bone = te->directdata; - - if (set != OL_SETSEL_NONE) { - if (!(bone->flag & BONE_HIDDEN_P)) { - Object *ob = OBACT(view_layer); - if (ob) { - if (set != OL_SETSEL_EXTEND) { - /* single select forces all other bones to get unselected */ - for (Bone *bone_iter = arm->bonebase.first; bone_iter != NULL; bone_iter = bone_iter->next) { - bone_iter->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); - do_outliner_bone_select_recursive(arm, bone_iter, false); - } - } - } - - if (set == OL_SETSEL_EXTEND && (bone->flag & BONE_SELECTED)) { - bone->flag &= ~BONE_SELECTED; - } - else { - bone->flag |= BONE_SELECTED; - arm->act_bone = bone; - } - - if (recursive) { - /* Recursive select/deselect */ - do_outliner_bone_select_recursive(arm, bone, (bone->flag & BONE_SELECTED) != 0); - } - - - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, ob); - } - } - else { - Object *ob = OBACT(view_layer); - - if (ob && ob->data == arm) { - if (bone->flag & BONE_SELECTED) { - return OL_DRAWSEL_NORMAL; - } - } - } - return OL_DRAWSEL_NONE; + bArmature *arm = (bArmature *)tselem->id; + Bone *bone = te->directdata; + + if (set != OL_SETSEL_NONE) { + if (!(bone->flag & BONE_HIDDEN_P)) { + Object *ob = OBACT(view_layer); + if (ob) { + if (set != OL_SETSEL_EXTEND) { + /* single select forces all other bones to get unselected */ + for (Bone *bone_iter = arm->bonebase.first; bone_iter != NULL; + bone_iter = bone_iter->next) { + bone_iter->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); + do_outliner_bone_select_recursive(arm, bone_iter, false); + } + } + } + + if (set == OL_SETSEL_EXTEND && (bone->flag & BONE_SELECTED)) { + bone->flag &= ~BONE_SELECTED; + } + else { + bone->flag |= BONE_SELECTED; + arm->act_bone = bone; + } + + if (recursive) { + /* Recursive select/deselect */ + do_outliner_bone_select_recursive(arm, bone, (bone->flag & BONE_SELECTED) != 0); + } + + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, ob); + } + } + else { + Object *ob = OBACT(view_layer); + + if (ob && ob->data == arm) { + if (bone->flag & BONE_SELECTED) { + return OL_DRAWSEL_NORMAL; + } + } + } + return OL_DRAWSEL_NONE; } - /* ebones only draw in editmode armature */ static void tree_element_active_ebone__sel(bContext *C, bArmature *arm, EditBone *ebone, short sel) { - if (sel) { - ebone->flag |= BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL; - arm->act_edbone = ebone; - // flush to parent? - if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { - ebone->parent->flag |= BONE_TIPSEL; - } - } - else { - ebone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL); - // flush to parent? - if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { - ebone->parent->flag &= ~BONE_TIPSEL; - } - } - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, CTX_data_edit_object(C)); + if (sel) { + ebone->flag |= BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL; + arm->act_edbone = ebone; + // flush to parent? + if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { + ebone->parent->flag |= BONE_TIPSEL; + } + } + else { + ebone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL); + // flush to parent? + if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { + ebone->parent->flag &= ~BONE_TIPSEL; + } + } + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_ACTIVE, CTX_data_edit_object(C)); } -static eOLDrawState tree_element_active_ebone( - bContext *C, ViewLayer *view_layer, TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive) +static eOLDrawState tree_element_active_ebone(bContext *C, + ViewLayer *view_layer, + TreeElement *te, + TreeStoreElem *tselem, + const eOLSetState set, + bool recursive) { - bArmature *arm = (bArmature *)tselem->id; - EditBone *ebone = te->directdata; - eOLDrawState status = OL_DRAWSEL_NONE; - - if (set != OL_SETSEL_NONE) { - if (set == OL_SETSEL_NORMAL) { - if (!(ebone->flag & BONE_HIDDEN_A)) { - uint bases_len = 0; - Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data(view_layer, NULL, &bases_len); - ED_armature_edit_deselect_all_multi_ex(bases, bases_len); - MEM_freeN(bases); - - tree_element_active_ebone__sel(C, arm, ebone, true); - status = OL_DRAWSEL_NORMAL; - } - } - else if (set == OL_SETSEL_EXTEND) { - if (!(ebone->flag & BONE_HIDDEN_A)) { - if (!(ebone->flag & BONE_SELECTED)) { - tree_element_active_ebone__sel(C, arm, ebone, true); - status = OL_DRAWSEL_NORMAL; - } - else { - /* entirely selected, so de-select */ - tree_element_active_ebone__sel(C, arm, ebone, false); - status = OL_DRAWSEL_NONE; - } - } - } - - if (recursive) { - /* Recursive select/deselect */ - do_outliner_ebone_select_recursive(arm, ebone, (ebone->flag & BONE_SELECTED) != 0); - } - } - else if (ebone->flag & BONE_SELECTED) { - status = OL_DRAWSEL_NORMAL; - } - - return status; + bArmature *arm = (bArmature *)tselem->id; + EditBone *ebone = te->directdata; + eOLDrawState status = OL_DRAWSEL_NONE; + + if (set != OL_SETSEL_NONE) { + if (set == OL_SETSEL_NORMAL) { + if (!(ebone->flag & BONE_HIDDEN_A)) { + uint bases_len = 0; + Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( + view_layer, NULL, &bases_len); + ED_armature_edit_deselect_all_multi_ex(bases, bases_len); + MEM_freeN(bases); + + tree_element_active_ebone__sel(C, arm, ebone, true); + status = OL_DRAWSEL_NORMAL; + } + } + else if (set == OL_SETSEL_EXTEND) { + if (!(ebone->flag & BONE_HIDDEN_A)) { + if (!(ebone->flag & BONE_SELECTED)) { + tree_element_active_ebone__sel(C, arm, ebone, true); + status = OL_DRAWSEL_NORMAL; + } + else { + /* entirely selected, so de-select */ + tree_element_active_ebone__sel(C, arm, ebone, false); + status = OL_DRAWSEL_NONE; + } + } + } + + if (recursive) { + /* Recursive select/deselect */ + do_outliner_ebone_select_recursive(arm, ebone, (ebone->flag & BONE_SELECTED) != 0); + } + } + else if (ebone->flag & BONE_SELECTED) { + status = OL_DRAWSEL_NORMAL; + } + + return status; } -static eOLDrawState tree_element_active_modifier( - bContext *C, Scene *UNUSED(scene), ViewLayer *UNUSED(sl), TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) +static eOLDrawState tree_element_active_modifier(bContext *C, + Scene *UNUSED(scene), + ViewLayer *UNUSED(sl), + TreeElement *UNUSED(te), + TreeStoreElem *tselem, + const eOLSetState set) { - if (set != OL_SETSEL_NONE) { - Object *ob = (Object *)tselem->id; + if (set != OL_SETSEL_NONE) { + Object *ob = (Object *)tselem->id; - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); -// XXX extern_set_butspace(F9KEY, 0); - } + // XXX extern_set_butspace(F9KEY, 0); + } - return OL_DRAWSEL_NONE; + return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_psys( - bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) +static eOLDrawState tree_element_active_psys(bContext *C, + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *tselem, + const eOLSetState set) { - if (set != OL_SETSEL_NONE) { - Object *ob = (Object *)tselem->id; + if (set != OL_SETSEL_NONE) { + Object *ob = (Object *)tselem->id; - WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_EDITED, ob); -// XXX extern_set_butspace(F7KEY, 0); - } + // XXX extern_set_butspace(F7KEY, 0); + } - return OL_DRAWSEL_NONE; + return OL_DRAWSEL_NONE; } -static int tree_element_active_constraint( - bContext *C, Scene *UNUSED(scene), ViewLayer *UNUSED(sl), TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) +static int tree_element_active_constraint(bContext *C, + Scene *UNUSED(scene), + ViewLayer *UNUSED(sl), + TreeElement *UNUSED(te), + TreeStoreElem *tselem, + const eOLSetState set) { - if (set != OL_SETSEL_NONE) { - Object *ob = (Object *)tselem->id; + if (set != OL_SETSEL_NONE) { + Object *ob = (Object *)tselem->id; - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); -// XXX extern_set_butspace(F7KEY, 0); - } + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); + // XXX extern_set_butspace(F7KEY, 0); + } - return OL_DRAWSEL_NONE; + return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_text( - bContext *UNUSED(C), Scene *UNUSED(scene), ViewLayer *UNUSED(sl), SpaceOutliner *UNUSED(soops), - TreeElement *UNUSED(te), int UNUSED(set)) +static eOLDrawState tree_element_active_text(bContext *UNUSED(C), + Scene *UNUSED(scene), + ViewLayer *UNUSED(sl), + SpaceOutliner *UNUSED(soops), + TreeElement *UNUSED(te), + int UNUSED(set)) { - // XXX removed - return OL_DRAWSEL_NONE; + // XXX removed + return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_pose( - bContext *C, Scene *scene, ViewLayer *view_layer, TreeElement *UNUSED(te), TreeStoreElem *tselem, const eOLSetState set) +static eOLDrawState tree_element_active_pose(bContext *C, + Scene *scene, + ViewLayer *view_layer, + TreeElement *UNUSED(te), + TreeStoreElem *tselem, + const eOLSetState set) { - Object *ob = (Object *)tselem->id; - Base *base = BKE_view_layer_base_find(view_layer, ob); - - if (base == NULL) { - /* Armature not instantiated in current scene (e.g. inside an appended group...). */ - return OL_DRAWSEL_NONE; - } - - if (set != OL_SETSEL_NONE) { - do_outliner_activate_pose(C, scene, view_layer, base, (set == OL_SETSEL_EXTEND)); - } - else { - if (ob->mode & OB_MODE_POSE) { - return OL_DRAWSEL_NORMAL; - } - } - return OL_DRAWSEL_NONE; + Object *ob = (Object *)tselem->id; + Base *base = BKE_view_layer_base_find(view_layer, ob); + + if (base == NULL) { + /* Armature not instantiated in current scene (e.g. inside an appended group...). */ + return OL_DRAWSEL_NONE; + } + + if (set != OL_SETSEL_NONE) { + do_outliner_activate_pose(C, scene, view_layer, base, (set == OL_SETSEL_EXTEND)); + } + else { + if (ob->mode & OB_MODE_POSE) { + return OL_DRAWSEL_NORMAL; + } + } + return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_sequence( - bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), const eOLSetState set) +static eOLDrawState tree_element_active_sequence(bContext *C, + Scene *scene, + TreeElement *te, + TreeStoreElem *UNUSED(tselem), + const eOLSetState set) { - Sequence *seq = (Sequence *) te->directdata; - Editing *ed = BKE_sequencer_editing_get(scene, false); - - if (set != OL_SETSEL_NONE) { - /* only check on setting */ - if (BLI_findindex(ed->seqbasep, seq) != -1) { - if (set == OL_SETSEL_EXTEND) { - BKE_sequencer_active_set(scene, NULL); - } - ED_sequencer_deselect_all(scene); - - if ((set == OL_SETSEL_EXTEND) && seq->flag & SELECT) { - seq->flag &= ~SELECT; - } - else { - seq->flag |= SELECT; - BKE_sequencer_active_set(scene, seq); - } - } - - WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene); - } - else { - if (ed->act_seq == seq && seq->flag & SELECT) { - return OL_DRAWSEL_NORMAL; - } - } - return OL_DRAWSEL_NONE; + Sequence *seq = (Sequence *)te->directdata; + Editing *ed = BKE_sequencer_editing_get(scene, false); + + if (set != OL_SETSEL_NONE) { + /* only check on setting */ + if (BLI_findindex(ed->seqbasep, seq) != -1) { + if (set == OL_SETSEL_EXTEND) { + BKE_sequencer_active_set(scene, NULL); + } + ED_sequencer_deselect_all(scene); + + if ((set == OL_SETSEL_EXTEND) && seq->flag & SELECT) { + seq->flag &= ~SELECT; + } + else { + seq->flag |= SELECT; + BKE_sequencer_active_set(scene, seq); + } + } + + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene); + } + else { + if (ed->act_seq == seq && seq->flag & SELECT) { + return OL_DRAWSEL_NORMAL; + } + } + return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_sequence_dup( - Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tselem), const eOLSetState set) +static eOLDrawState tree_element_active_sequence_dup(Scene *scene, + TreeElement *te, + TreeStoreElem *UNUSED(tselem), + const eOLSetState set) { - Sequence *seq, *p; - Editing *ed = BKE_sequencer_editing_get(scene, false); - - seq = (Sequence *)te->directdata; - if (set == OL_SETSEL_NONE) { - if (seq->flag & SELECT) { - return OL_DRAWSEL_NORMAL; - } - return OL_DRAWSEL_NONE; - } - -// XXX select_single_seq(seq, 1); - p = ed->seqbasep->first; - while (p) { - if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) { - p = p->next; - continue; - } - -// if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) -// XXX select_single_seq(p, 0); - p = p->next; - } - return OL_DRAWSEL_NONE; + Sequence *seq, *p; + Editing *ed = BKE_sequencer_editing_get(scene, false); + + seq = (Sequence *)te->directdata; + if (set == OL_SETSEL_NONE) { + if (seq->flag & SELECT) { + return OL_DRAWSEL_NORMAL; + } + return OL_DRAWSEL_NONE; + } + + // XXX select_single_seq(seq, 1); + p = ed->seqbasep->first; + while (p) { + if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) { + p = p->next; + continue; + } + + // if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) + // XXX select_single_seq(p, 0); + p = p->next; + } + return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_keymap_item( - bContext *UNUSED(C), Scene *UNUSED(scene), ViewLayer *UNUSED(sl), TreeElement *te, TreeStoreElem *UNUSED(tselem), const eOLSetState set) +static eOLDrawState tree_element_active_keymap_item(bContext *UNUSED(C), + Scene *UNUSED(scene), + ViewLayer *UNUSED(sl), + TreeElement *te, + TreeStoreElem *UNUSED(tselem), + const eOLSetState set) { - wmKeyMapItem *kmi = te->directdata; - - if (set == OL_SETSEL_NONE) { - if (kmi->flag & KMI_INACTIVE) { - return OL_DRAWSEL_NONE; - } - return OL_DRAWSEL_NORMAL; - } - else { - kmi->flag ^= KMI_INACTIVE; - } - return OL_DRAWSEL_NONE; + wmKeyMapItem *kmi = te->directdata; + + if (set == OL_SETSEL_NONE) { + if (kmi->flag & KMI_INACTIVE) { + return OL_DRAWSEL_NONE; + } + return OL_DRAWSEL_NORMAL; + } + else { + kmi->flag ^= KMI_INACTIVE; + } + return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_master_collection( - bContext *C, TreeElement *UNUSED(te), const eOLSetState set) +static eOLDrawState tree_element_active_master_collection(bContext *C, + TreeElement *UNUSED(te), + const eOLSetState set) { - if (set == OL_SETSEL_NONE) { - ViewLayer *view_layer = CTX_data_view_layer(C); - LayerCollection *active = CTX_data_layer_collection(C); - - if (active == view_layer->layer_collections.first) { - return OL_DRAWSEL_NORMAL; - } - } - else { - ViewLayer *view_layer = CTX_data_view_layer(C); - LayerCollection *layer_collection = view_layer->layer_collections.first; - BKE_layer_collection_activate(view_layer, layer_collection); - WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); - } - - return OL_DRAWSEL_NONE; + if (set == OL_SETSEL_NONE) { + ViewLayer *view_layer = CTX_data_view_layer(C); + LayerCollection *active = CTX_data_layer_collection(C); + + if (active == view_layer->layer_collections.first) { + return OL_DRAWSEL_NORMAL; + } + } + else { + ViewLayer *view_layer = CTX_data_view_layer(C); + LayerCollection *layer_collection = view_layer->layer_collections.first; + BKE_layer_collection_activate(view_layer, layer_collection); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + } + + return OL_DRAWSEL_NONE; } -static eOLDrawState tree_element_active_layer_collection( - bContext *C, TreeElement *te, const eOLSetState set) +static eOLDrawState tree_element_active_layer_collection(bContext *C, + TreeElement *te, + const eOLSetState set) { - if (set == OL_SETSEL_NONE) { - LayerCollection *active = CTX_data_layer_collection(C); - - if (active == te->directdata) { - return OL_DRAWSEL_NORMAL; - } - } - else { - Scene *scene = CTX_data_scene(C); - LayerCollection *layer_collection = te->directdata; - ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection); - BKE_layer_collection_activate(view_layer, layer_collection); - WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); - } - - return OL_DRAWSEL_NONE; + if (set == OL_SETSEL_NONE) { + LayerCollection *active = CTX_data_layer_collection(C); + + if (active == te->directdata) { + return OL_DRAWSEL_NORMAL; + } + } + else { + Scene *scene = CTX_data_scene(C); + LayerCollection *layer_collection = te->directdata; + ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection); + BKE_layer_collection_activate(view_layer, layer_collection); + WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + } + + return OL_DRAWSEL_NONE; } /* ---------------------------------------------- */ /* generic call for ID data check or make/check active in UI */ -eOLDrawState tree_element_active(bContext *C, Scene *scene, ViewLayer *view_layer, SpaceOutliner *soops, TreeElement *te, - const eOLSetState set, const bool handle_all_types) +eOLDrawState tree_element_active(bContext *C, + Scene *scene, + ViewLayer *view_layer, + SpaceOutliner *soops, + TreeElement *te, + const eOLSetState set, + const bool handle_all_types) { - switch (te->idcode) { - /* Note: ID_OB only if handle_all_type is true, else objects are handled specially to allow multiple - * selection. See do_outliner_item_activate. */ - case ID_OB: - if (handle_all_types) { - return tree_element_set_active_object(C, scene, view_layer, soops, te, set, false); - } - break; - case ID_MA: - return tree_element_active_material(C, scene, view_layer, soops, te, set); - case ID_WO: - return tree_element_active_world(C, scene, view_layer, soops, te, set); - case ID_LA: - return tree_element_active_light(C, scene, view_layer, soops, te, set); - case ID_TXT: - return tree_element_active_text(C, scene, view_layer, soops, te, set); - case ID_CA: - return tree_element_active_camera(C, scene, view_layer, soops, te, set); - } - return OL_DRAWSEL_NONE; + switch (te->idcode) { + /* Note: ID_OB only if handle_all_type is true, else objects are handled specially to allow multiple + * selection. See do_outliner_item_activate. */ + case ID_OB: + if (handle_all_types) { + return tree_element_set_active_object(C, scene, view_layer, soops, te, set, false); + } + break; + case ID_MA: + return tree_element_active_material(C, scene, view_layer, soops, te, set); + case ID_WO: + return tree_element_active_world(C, scene, view_layer, soops, te, set); + case ID_LA: + return tree_element_active_light(C, scene, view_layer, soops, te, set); + case ID_TXT: + return tree_element_active_text(C, scene, view_layer, soops, te, set); + case ID_CA: + return tree_element_active_camera(C, scene, view_layer, soops, te, set); + } + return OL_DRAWSEL_NONE; } /** * Generic call for non-id data to make/check active in UI */ -eOLDrawState tree_element_type_active( - bContext *C, Scene *scene, ViewLayer *view_layer, SpaceOutliner *soops, - TreeElement *te, TreeStoreElem *tselem, const eOLSetState set, bool recursive) +eOLDrawState tree_element_type_active(bContext *C, + Scene *scene, + ViewLayer *view_layer, + SpaceOutliner *soops, + TreeElement *te, + TreeStoreElem *tselem, + const eOLSetState set, + bool recursive) { - switch (tselem->type) { - case TSE_DEFGROUP: - return tree_element_active_defgroup(C, view_layer, te, tselem, set); - case TSE_BONE: - return tree_element_active_bone(C, view_layer, te, tselem, set, recursive); - case TSE_EBONE: - return tree_element_active_ebone(C, view_layer, te, tselem, set, recursive); - case TSE_MODIFIER: - return tree_element_active_modifier(C, scene, view_layer, te, tselem, set); - case TSE_LINKED_OB: - if (set != OL_SETSEL_NONE) { - tree_element_set_active_object(C, scene, view_layer, soops, te, set, false); - } - else if (tselem->id == (ID *)OBACT(view_layer)) { - return OL_DRAWSEL_NORMAL; - } - break; - case TSE_LINKED_PSYS: - return tree_element_active_psys(C, scene, te, tselem, set); - case TSE_POSE_BASE: - return tree_element_active_pose(C, scene, view_layer, te, tselem, set); - case TSE_POSE_CHANNEL: - return tree_element_active_posechannel(C, scene, view_layer, te, tselem, set, recursive); - case TSE_CONSTRAINT: - return tree_element_active_constraint(C, scene, view_layer, te, tselem, set); - case TSE_R_LAYER: - return active_viewlayer(C, scene, view_layer, te, set); - case TSE_POSEGRP: - return tree_element_active_posegroup(C, scene, view_layer, te, tselem, set); - case TSE_SEQUENCE: - return tree_element_active_sequence(C, scene, te, tselem, set); - case TSE_SEQUENCE_DUP: - return tree_element_active_sequence_dup(scene, te, tselem, set); - case TSE_KEYMAP_ITEM: - return tree_element_active_keymap_item(C, scene, view_layer, te, tselem, set); - case TSE_GP_LAYER: - return tree_element_active_gplayer(C, scene, te, tselem, set); - break; - case TSE_VIEW_COLLECTION_BASE: - return tree_element_active_master_collection(C, te, set); - case TSE_LAYER_COLLECTION: - return tree_element_active_layer_collection(C, te, set); - } - return OL_DRAWSEL_NONE; + switch (tselem->type) { + case TSE_DEFGROUP: + return tree_element_active_defgroup(C, view_layer, te, tselem, set); + case TSE_BONE: + return tree_element_active_bone(C, view_layer, te, tselem, set, recursive); + case TSE_EBONE: + return tree_element_active_ebone(C, view_layer, te, tselem, set, recursive); + case TSE_MODIFIER: + return tree_element_active_modifier(C, scene, view_layer, te, tselem, set); + case TSE_LINKED_OB: + if (set != OL_SETSEL_NONE) { + tree_element_set_active_object(C, scene, view_layer, soops, te, set, false); + } + else if (tselem->id == (ID *)OBACT(view_layer)) { + return OL_DRAWSEL_NORMAL; + } + break; + case TSE_LINKED_PSYS: + return tree_element_active_psys(C, scene, te, tselem, set); + case TSE_POSE_BASE: + return tree_element_active_pose(C, scene, view_layer, te, tselem, set); + case TSE_POSE_CHANNEL: + return tree_element_active_posechannel(C, scene, view_layer, te, tselem, set, recursive); + case TSE_CONSTRAINT: + return tree_element_active_constraint(C, scene, view_layer, te, tselem, set); + case TSE_R_LAYER: + return active_viewlayer(C, scene, view_layer, te, set); + case TSE_POSEGRP: + return tree_element_active_posegroup(C, scene, view_layer, te, tselem, set); + case TSE_SEQUENCE: + return tree_element_active_sequence(C, scene, te, tselem, set); + case TSE_SEQUENCE_DUP: + return tree_element_active_sequence_dup(scene, te, tselem, set); + case TSE_KEYMAP_ITEM: + return tree_element_active_keymap_item(C, scene, view_layer, te, tselem, set); + case TSE_GP_LAYER: + return tree_element_active_gplayer(C, scene, te, tselem, set); + break; + case TSE_VIEW_COLLECTION_BASE: + return tree_element_active_master_collection(C, te, set); + case TSE_LAYER_COLLECTION: + return tree_element_active_layer_collection(C, te, set); + } + return OL_DRAWSEL_NONE; } /* ================================================ */ @@ -1031,143 +1115,162 @@ eOLDrawState tree_element_type_active( * * Needed to run from operators accessed from a menu. */ -static void do_outliner_item_activate_tree_element( - bContext *C, Scene *scene, ViewLayer *view_layer, SpaceOutliner *soops, - TreeElement *te, TreeStoreElem *tselem, - const bool extend, const bool recursive) +static void do_outliner_item_activate_tree_element(bContext *C, + Scene *scene, + ViewLayer *view_layer, + SpaceOutliner *soops, + TreeElement *te, + TreeStoreElem *tselem, + const bool extend, + const bool recursive) { - /* Always makes active object, except for some specific types. */ - if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP, TSE_EBONE, TSE_LAYER_COLLECTION)) { - /* Note about TSE_EBONE: In case of a same ID_AR datablock shared among several objects, we do not want - * to switch out of edit mode (see T48328 for details). */ - } - else if (tselem->id && OB_DATA_SUPPORT_EDITMODE(te->idcode)) { - /* Support edit-mode toggle, keeping the active object as is. */ - } - else if (tselem->type == TSE_POSE_BASE) { - /* Support pose mode toggle, keeping the active object as is. */ - } - else { - tree_element_set_active_object( - C, scene, view_layer, soops, te, - (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, - recursive && tselem->type == 0); - } - - if (tselem->type == 0) { // the lib blocks - /* editmode? */ - if (te->idcode == ID_SCE) { - if (scene != (Scene *)tselem->id) { - WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), (Scene *)tselem->id); - } - } - else if (te->idcode == ID_GR) { - Collection *gr = (Collection *)tselem->id; - - if (extend) { - int sel = BA_SELECT; - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(gr, object) - { - Base *base = BKE_view_layer_base_find(view_layer, object); - if (base && (base->flag & BASE_SELECTED)) { - sel = BA_DESELECT; - break; - } - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(gr, object) - { - Base *base = BKE_view_layer_base_find(view_layer, object); - if (base) { - ED_object_base_select(base, sel); - } - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - } - else { - BKE_view_layer_base_deselect_all(view_layer); - - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(gr, object) - { - Base *base = BKE_view_layer_base_find(view_layer, object); - /* Object may not be in this scene */ - if (base != NULL) { - if ((base->flag & BASE_SELECTED) == 0) { - ED_object_base_select(base, BA_SELECT); - } - } - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - } - - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } - else if (OB_DATA_SUPPORT_EDITMODE(te->idcode)) { - Object *ob = (Object *)outliner_search_back(soops, te, ID_OB); - if ((ob != NULL) && (ob->data == tselem->id)) { - Base *base = BKE_view_layer_base_find(view_layer, ob); - if ((base != NULL) && (base->flag & BASE_VISIBLE)) { - do_outliner_activate_obdata(C, scene, view_layer, base, extend); - } - } - } - else if (ELEM(te->idcode, ID_GD)) { - /* set grease pencil to object mode */ - WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); - } - else { // rest of types - tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, false); - } - - } - else { - tree_element_type_active(C, scene, view_layer, soops, te, tselem, - extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, - recursive); - } + /* Always makes active object, except for some specific types. */ + if (ELEM(tselem->type, + TSE_SEQUENCE, + TSE_SEQ_STRIP, + TSE_SEQUENCE_DUP, + TSE_EBONE, + TSE_LAYER_COLLECTION)) { + /* Note about TSE_EBONE: In case of a same ID_AR datablock shared among several objects, we do not want + * to switch out of edit mode (see T48328 for details). */ + } + else if (tselem->id && OB_DATA_SUPPORT_EDITMODE(te->idcode)) { + /* Support edit-mode toggle, keeping the active object as is. */ + } + else if (tselem->type == TSE_POSE_BASE) { + /* Support pose mode toggle, keeping the active object as is. */ + } + else { + tree_element_set_active_object(C, + scene, + view_layer, + soops, + te, + (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : + OL_SETSEL_NORMAL, + recursive && tselem->type == 0); + } + + if (tselem->type == 0) { // the lib blocks + /* editmode? */ + if (te->idcode == ID_SCE) { + if (scene != (Scene *)tselem->id) { + WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), (Scene *)tselem->id); + } + } + else if (te->idcode == ID_GR) { + Collection *gr = (Collection *)tselem->id; + + if (extend) { + int sel = BA_SELECT; + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (gr, object) { + Base *base = BKE_view_layer_base_find(view_layer, object); + if (base && (base->flag & BASE_SELECTED)) { + sel = BA_DESELECT; + break; + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (gr, object) { + Base *base = BKE_view_layer_base_find(view_layer, object); + if (base) { + ED_object_base_select(base, sel); + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } + else { + BKE_view_layer_base_deselect_all(view_layer); + + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (gr, object) { + Base *base = BKE_view_layer_base_find(view_layer, object); + /* Object may not be in this scene */ + if (base != NULL) { + if ((base->flag & BASE_SELECTED) == 0) { + ED_object_base_select(base, BA_SELECT); + } + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } + + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + } + else if (OB_DATA_SUPPORT_EDITMODE(te->idcode)) { + Object *ob = (Object *)outliner_search_back(soops, te, ID_OB); + if ((ob != NULL) && (ob->data == tselem->id)) { + Base *base = BKE_view_layer_base_find(view_layer, ob); + if ((base != NULL) && (base->flag & BASE_VISIBLE)) { + do_outliner_activate_obdata(C, scene, view_layer, base, extend); + } + } + } + else if (ELEM(te->idcode, ID_GD)) { + /* set grease pencil to object mode */ + WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL); + } + else { // rest of types + tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, false); + } + } + else { + tree_element_type_active(C, + scene, + view_layer, + soops, + te, + tselem, + extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, + recursive); + } } /** * \param extend: Don't deselect other items, only modify \a te. * \param toggle: Select \a te when not selected, deselect when selected. */ -void outliner_item_select(SpaceOutliner *soops, const TreeElement *te, const bool extend, const bool toggle) +void outliner_item_select(SpaceOutliner *soops, + const TreeElement *te, + const bool extend, + const bool toggle) { - TreeStoreElem *tselem = TREESTORE(te); - const short new_flag = toggle ? (tselem->flag ^ TSE_SELECTED) : (tselem->flag | TSE_SELECTED); + TreeStoreElem *tselem = TREESTORE(te); + const short new_flag = toggle ? (tselem->flag ^ TSE_SELECTED) : (tselem->flag | TSE_SELECTED); - if (extend == false) { - outliner_flag_set(&soops->tree, TSE_SELECTED, false); - } - tselem->flag = new_flag; + if (extend == false) { + outliner_flag_set(&soops->tree, TSE_SELECTED, false); + } + tselem->flag = new_flag; } static void outliner_item_toggle_closed(TreeElement *te, const bool toggle_children) { - TreeStoreElem *tselem = TREESTORE(te); - if (toggle_children) { - tselem->flag &= ~TSE_CLOSED; - - const bool all_opened = !outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1); - outliner_flag_set(&te->subtree, TSE_CLOSED, all_opened); - } - else { - tselem->flag ^= TSE_CLOSED; - } + TreeStoreElem *tselem = TREESTORE(te); + if (toggle_children) { + tselem->flag &= ~TSE_CLOSED; + + const bool all_opened = !outliner_flag_is_any_test(&te->subtree, TSE_CLOSED, 1); + outliner_flag_set(&te->subtree, TSE_CLOSED, all_opened); + } + else { + tselem->flag ^= TSE_CLOSED; + } } static bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x) { - return ((te->flag & TE_ICONROW) == 0) && (view_co_x > te->xs) && (view_co_x < te->xs + UI_UNIT_X); + return ((te->flag & TE_ICONROW) == 0) && (view_co_x > te->xs) && + (view_co_x < te->xs + UI_UNIT_X); } -static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *soops, const ARegion *ar, float view_co_x) +static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *soops, + const ARegion *ar, + float view_co_x) { - return ((soops->outlinevis != SO_DATA_API) && - !(soops->flag & SO_HIDE_RESTRICTCOLS) && - (view_co_x > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX)); + return ((soops->outlinevis != SO_DATA_API) && !(soops->flag & SO_HIDE_RESTRICTCOLS) && + (view_co_x > ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX)); } /** @@ -1177,17 +1280,14 @@ static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *soops, c * This allows us to simulate clicking on an item without dealing with the mouse cursor. */ void outliner_item_do_activate_from_tree_element( - bContext *C, TreeElement *te, TreeStoreElem *tselem, - bool extend, bool recursive) + bContext *C, TreeElement *te, TreeStoreElem *tselem, bool extend, bool recursive) { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - - do_outliner_item_activate_tree_element( - C, scene, view_layer, soops, - te, tselem, - extend, recursive); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + + do_outliner_item_activate_tree_element( + C, scene, view_layer, soops, te, tselem, extend, recursive); } /** @@ -1195,149 +1295,152 @@ void outliner_item_do_activate_from_tree_element( * * May expend/collapse branches or activate items. * */ -int outliner_item_do_activate_from_cursor( - bContext *C, const int mval[2], - bool extend, bool recursive) +int outliner_item_do_activate_from_cursor(bContext *C, + const int mval[2], + bool extend, + bool recursive) { - ARegion *ar = CTX_wm_region(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - TreeElement *te; - float view_mval[2]; - bool changed = false, rebuild_tree = false; - - UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]); - - if (outliner_is_co_within_restrict_columns(soops, ar, view_mval[0])) { - return OPERATOR_CANCELLED; - } - - if (!(te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]))) { - /* skip */ - } - else if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) { - outliner_item_toggle_closed(te, extend); - changed = true; - rebuild_tree = true; - } - else { - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - /* the row may also contain children, if one is hovered we want this instead of current te */ - TreeElement *activate_te = outliner_find_item_at_x_in_row(soops, te, view_mval[0]); - TreeStoreElem *activate_tselem = TREESTORE(activate_te); - - outliner_item_select(soops, activate_te, extend, extend); - do_outliner_item_activate_tree_element(C, scene, view_layer, soops, activate_te, activate_tselem, extend, recursive); - changed = true; - } - - if (changed) { - if (rebuild_tree) { - ED_region_tag_redraw(ar); - } - else { - ED_region_tag_redraw_no_rebuild(ar); - } - ED_undo_push(C, "Outliner selection change"); - } - - return OPERATOR_FINISHED; + ARegion *ar = CTX_wm_region(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + TreeElement *te; + float view_mval[2]; + bool changed = false, rebuild_tree = false; + + UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]); + + if (outliner_is_co_within_restrict_columns(soops, ar, view_mval[0])) { + return OPERATOR_CANCELLED; + } + + if (!(te = outliner_find_item_at_y(soops, &soops->tree, view_mval[1]))) { + /* skip */ + } + else if (outliner_item_is_co_within_close_toggle(te, view_mval[0])) { + outliner_item_toggle_closed(te, extend); + changed = true; + rebuild_tree = true; + } + else { + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + /* the row may also contain children, if one is hovered we want this instead of current te */ + TreeElement *activate_te = outliner_find_item_at_x_in_row(soops, te, view_mval[0]); + TreeStoreElem *activate_tselem = TREESTORE(activate_te); + + outliner_item_select(soops, activate_te, extend, extend); + do_outliner_item_activate_tree_element( + C, scene, view_layer, soops, activate_te, activate_tselem, extend, recursive); + changed = true; + } + + if (changed) { + if (rebuild_tree) { + ED_region_tag_redraw(ar); + } + else { + ED_region_tag_redraw_no_rebuild(ar); + } + ED_undo_push(C, "Outliner selection change"); + } + + return OPERATOR_FINISHED; } /* event can enterkey, then it opens/closes */ static int outliner_item_activate_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - bool extend = RNA_boolean_get(op->ptr, "extend"); - bool recursive = RNA_boolean_get(op->ptr, "recursive"); - return outliner_item_do_activate_from_cursor(C, event->mval, extend, recursive); + bool extend = RNA_boolean_get(op->ptr, "extend"); + bool recursive = RNA_boolean_get(op->ptr, "recursive"); + return outliner_item_do_activate_from_cursor(C, event->mval, extend, recursive); } void OUTLINER_OT_item_activate(wmOperatorType *ot) { - ot->name = "Select"; - ot->idname = "OUTLINER_OT_item_activate"; - ot->description = "Handle mouse clicks to select and activate items"; + ot->name = "Select"; + ot->idname = "OUTLINER_OT_item_activate"; + ot->description = "Handle mouse clicks to select and activate items"; - ot->invoke = outliner_item_activate_invoke; + ot->invoke = outliner_item_activate_invoke; - ot->poll = ED_operator_outliner_active; + ot->poll = ED_operator_outliner_active; - RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection for activation"); - RNA_def_boolean(ot->srna, "recursive", false, "Recursive", "Select Objects and their children"); + RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection for activation"); + RNA_def_boolean(ot->srna, "recursive", false, "Recursive", "Select Objects and their children"); } /* ****************************************************** */ /* **************** Box Select Tool ****************** */ -static void outliner_item_box_select(SpaceOutliner *soops, Scene *scene, rctf *rectf, TreeElement *te, bool select) +static void outliner_item_box_select( + SpaceOutliner *soops, Scene *scene, rctf *rectf, TreeElement *te, bool select) { - TreeStoreElem *tselem = TREESTORE(te); - - if (te->ys <= rectf->ymax && te->ys + UI_UNIT_Y >= rectf->ymin) { - if (select) { - tselem->flag |= TSE_SELECTED; - } - else { - tselem->flag &= ~TSE_SELECTED; - } - } - - /* Look at its children. */ - if (TSELEM_OPEN(tselem, soops)) { - for (te = te->subtree.first; te; te = te->next) { - outliner_item_box_select(soops, scene, rectf, te, select); - } - } + TreeStoreElem *tselem = TREESTORE(te); + + if (te->ys <= rectf->ymax && te->ys + UI_UNIT_Y >= rectf->ymin) { + if (select) { + tselem->flag |= TSE_SELECTED; + } + else { + tselem->flag &= ~TSE_SELECTED; + } + } + + /* Look at its children. */ + if (TSELEM_OPEN(tselem, soops)) { + for (te = te->subtree.first; te; te = te->next) { + outliner_item_box_select(soops, scene, rectf, te, select); + } + } } static int outliner_box_select_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - ARegion *ar = CTX_wm_region(C); - rctf rectf; + Scene *scene = CTX_data_scene(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + ARegion *ar = CTX_wm_region(C); + rctf rectf; - const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - const bool select = (sel_op != SEL_OP_SUB); - if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - outliner_flag_set(&soops->tree, TSE_SELECTED, 0); - } + const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); + const bool select = (sel_op != SEL_OP_SUB); + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + outliner_flag_set(&soops->tree, TSE_SELECTED, 0); + } - WM_operator_properties_border_to_rctf(op, &rectf); - UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf); + WM_operator_properties_border_to_rctf(op, &rectf); + UI_view2d_region_to_view_rctf(&ar->v2d, &rectf, &rectf); - for (TreeElement *te = soops->tree.first; te; te = te->next) { - outliner_item_box_select(soops, scene, &rectf, te, select); - } + for (TreeElement *te = soops->tree.first; te; te = te->next) { + outliner_item_box_select(soops, scene, &rectf, te, select); + } - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - ED_region_tag_redraw(ar); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + ED_region_tag_redraw(ar); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_select_box(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Box Select"; - ot->idname = "OUTLINER_OT_select_box"; - ot->description = "Use box selection to select tree elements"; + /* identifiers */ + ot->name = "Box Select"; + ot->idname = "OUTLINER_OT_select_box"; + ot->description = "Use box selection to select tree elements"; - /* api callbacks */ - ot->invoke = WM_gesture_box_invoke; - ot->exec = outliner_box_select_exec; - ot->modal = WM_gesture_box_modal; - ot->cancel = WM_gesture_box_cancel; + /* api callbacks */ + ot->invoke = WM_gesture_box_invoke; + ot->exec = outliner_box_select_exec; + ot->modal = WM_gesture_box_modal; + ot->cancel = WM_gesture_box_cancel; - ot->poll = ED_operator_outliner_active; + ot->poll = ED_operator_outliner_active; - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - /* properties */ - WM_operator_properties_gesture_box(ot); - WM_operator_properties_select_operation_simple(ot); + /* properties */ + WM_operator_properties_gesture_box(ot); + WM_operator_properties_select_operation_simple(ot); } /* ****************************************************** */ diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 083ae3a048c..ad4661102bc 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -82,2041 +82,2222 @@ #include "outliner_intern.h" - /* ****************************************************** */ /* ************ SELECTION OPERATIONS ********* */ -static void set_operation_types(SpaceOutliner *soops, ListBase *lb, +static void set_operation_types(SpaceOutliner *soops, + ListBase *lb, int *scenelevel, int *objectlevel, int *idlevel, int *datalevel) { - TreeElement *te; - TreeStoreElem *tselem; - - for (te = lb->first; te; te = te->next) { - tselem = TREESTORE(te); - if (tselem->flag & TSE_SELECTED) { - /* Layer collection points to collection ID. */ - if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { - if (*datalevel == 0) { - *datalevel = tselem->type; - } - else if (*datalevel != tselem->type) { - *datalevel = -1; - } - } - else { - int idcode = GS(tselem->id->name); - switch (idcode) { - case ID_SCE: - *scenelevel = 1; - break; - case ID_OB: - *objectlevel = 1; - break; - - case ID_ME: case ID_CU: case ID_MB: case ID_LT: - case ID_LA: case ID_AR: case ID_CA: case ID_SPK: - case ID_MA: case ID_TE: case ID_IP: case ID_IM: - case ID_SO: case ID_KE: case ID_WO: case ID_AC: - case ID_NLA: case ID_TXT: case ID_GR: case ID_LS: - case ID_LI: - if (*idlevel == 0) { - *idlevel = idcode; - } - else if (*idlevel != idcode) { - *idlevel = -1; - } - if (ELEM(*datalevel, TSE_VIEW_COLLECTION_BASE, TSE_SCENE_COLLECTION_BASE)) { - *datalevel = 0; - } - break; - } - } - } - if (TSELEM_OPEN(tselem, soops)) { - set_operation_types(soops, &te->subtree, - scenelevel, objectlevel, idlevel, datalevel); - } - } -} - -static void unlink_action_cb( - bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) -{ - /* just set action to NULL */ - BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, NULL); -} - -static void unlink_material_cb( - bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, - TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) -{ - Material **matar = NULL; - int a, totcol = 0; - - if (GS(tsep->id->name) == ID_OB) { - Object *ob = (Object *)tsep->id; - totcol = ob->totcol; - matar = ob->mat; - } - else if (GS(tsep->id->name) == ID_ME) { - Mesh *me = (Mesh *)tsep->id; - totcol = me->totcol; - matar = me->mat; - } - else if (GS(tsep->id->name) == ID_CU) { - Curve *cu = (Curve *)tsep->id; - totcol = cu->totcol; - matar = cu->mat; - } - else if (GS(tsep->id->name) == ID_MB) { - MetaBall *mb = (MetaBall *)tsep->id; - totcol = mb->totcol; - matar = mb->mat; - } - else { - BLI_assert(0); - } - - if (LIKELY(matar != NULL)) { - for (a = 0; a < totcol; a++) { - if (a == te->index && matar[a]) { - id_us_min(&matar[a]->id); - matar[a] = NULL; - } - } - } -} - -static void unlink_texture_cb( - bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, - TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) -{ - MTex **mtex = NULL; - int a; - - if (GS(tsep->id->name) == ID_LS) { - FreestyleLineStyle *ls = (FreestyleLineStyle *)tsep->id; - mtex = ls->mtex; - } - else { - return; - } - - for (a = 0; a < MAX_MTEX; a++) { - if (a == te->index && mtex[a]) { - if (mtex[a]->tex) { - id_us_min(&mtex[a]->tex->id); - mtex[a]->tex = NULL; - } - } - } -} - -static void unlink_collection_cb( - bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - Main *bmain = CTX_data_main(C); - Collection *collection = (Collection *)tselem->id; - - if (tsep) { - if (GS(tsep->id->name) == ID_OB) { - Object *ob = (Object *)tsep->id; - ob->instance_collection = NULL; - DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); - DEG_relations_tag_update(bmain); - } - else if (GS(tsep->id->name) == ID_GR) { - Collection *parent = (Collection *)tsep->id; - id_fake_user_set(&collection->id); - BKE_collection_child_remove(bmain, parent, collection); - DEG_id_tag_update(&parent->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); - } - else if (GS(tsep->id->name) == ID_SCE) { - Scene *scene = (Scene *)tsep->id; - Collection *parent = BKE_collection_master(scene); - id_fake_user_set(&collection->id); - BKE_collection_child_remove(bmain, parent, collection); - DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); - } - } -} - -static void unlink_object_cb( - bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - Main *bmain = CTX_data_main(C); - Object *ob = (Object *)tselem->id; - - if (tsep) { - if (GS(tsep->id->name) == ID_GR) { - Collection *parent = (Collection *)tsep->id; - BKE_collection_object_remove(bmain, parent, ob, true); - DEG_id_tag_update(&parent->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); - } - else if (GS(tsep->id->name) == ID_SCE) { - Scene *scene = (Scene *)tsep->id; - Collection *parent = BKE_collection_master(scene); - BKE_collection_object_remove(bmain, parent, ob, true); - DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); - DEG_relations_tag_update(bmain); - } - } -} - -static void unlink_world_cb( - bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - Scene *parscene = (Scene *)tsep->id; - World *wo = (World *)tselem->id; - - /* need to use parent scene not just scene, otherwise may end up getting wrong one */ - id_us_min(&wo->id); - parscene->world = NULL; -} - -static void outliner_do_libdata_operation( - bContext *C, ReportList *reports, Scene *scene, SpaceOutliner *soops, ListBase *lb, - outliner_operation_cb operation_cb, - void *user_data) -{ - TreeElement *te; - TreeStoreElem *tselem; - - for (te = lb->first; te; te = te->next) { - tselem = TREESTORE(te); - if (tselem->flag & TSE_SELECTED) { - if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { - TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL; - operation_cb(C, reports, scene, te, tsep, tselem, user_data); - } - } - if (TSELEM_OPEN(tselem, soops)) { - outliner_do_libdata_operation(C, reports, scene, soops, &te->subtree, operation_cb, user_data); - } - } + TreeElement *te; + TreeStoreElem *tselem; + + for (te = lb->first; te; te = te->next) { + tselem = TREESTORE(te); + if (tselem->flag & TSE_SELECTED) { + /* Layer collection points to collection ID. */ + if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { + if (*datalevel == 0) { + *datalevel = tselem->type; + } + else if (*datalevel != tselem->type) { + *datalevel = -1; + } + } + else { + int idcode = GS(tselem->id->name); + switch (idcode) { + case ID_SCE: + *scenelevel = 1; + break; + case ID_OB: + *objectlevel = 1; + break; + + case ID_ME: + case ID_CU: + case ID_MB: + case ID_LT: + case ID_LA: + case ID_AR: + case ID_CA: + case ID_SPK: + case ID_MA: + case ID_TE: + case ID_IP: + case ID_IM: + case ID_SO: + case ID_KE: + case ID_WO: + case ID_AC: + case ID_NLA: + case ID_TXT: + case ID_GR: + case ID_LS: + case ID_LI: + if (*idlevel == 0) { + *idlevel = idcode; + } + else if (*idlevel != idcode) { + *idlevel = -1; + } + if (ELEM(*datalevel, TSE_VIEW_COLLECTION_BASE, TSE_SCENE_COLLECTION_BASE)) { + *datalevel = 0; + } + break; + } + } + } + if (TSELEM_OPEN(tselem, soops)) { + set_operation_types(soops, &te->subtree, scenelevel, objectlevel, idlevel, datalevel); + } + } +} + +static void unlink_action_cb(bContext *C, + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *tsep, + TreeStoreElem *UNUSED(tselem), + void *UNUSED(user_data)) +{ + /* just set action to NULL */ + BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, NULL); +} + +static void unlink_material_cb(bContext *UNUSED(C), + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *te, + TreeStoreElem *tsep, + TreeStoreElem *UNUSED(tselem), + void *UNUSED(user_data)) +{ + Material **matar = NULL; + int a, totcol = 0; + + if (GS(tsep->id->name) == ID_OB) { + Object *ob = (Object *)tsep->id; + totcol = ob->totcol; + matar = ob->mat; + } + else if (GS(tsep->id->name) == ID_ME) { + Mesh *me = (Mesh *)tsep->id; + totcol = me->totcol; + matar = me->mat; + } + else if (GS(tsep->id->name) == ID_CU) { + Curve *cu = (Curve *)tsep->id; + totcol = cu->totcol; + matar = cu->mat; + } + else if (GS(tsep->id->name) == ID_MB) { + MetaBall *mb = (MetaBall *)tsep->id; + totcol = mb->totcol; + matar = mb->mat; + } + else { + BLI_assert(0); + } + + if (LIKELY(matar != NULL)) { + for (a = 0; a < totcol; a++) { + if (a == te->index && matar[a]) { + id_us_min(&matar[a]->id); + matar[a] = NULL; + } + } + } +} + +static void unlink_texture_cb(bContext *UNUSED(C), + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *te, + TreeStoreElem *tsep, + TreeStoreElem *UNUSED(tselem), + void *UNUSED(user_data)) +{ + MTex **mtex = NULL; + int a; + + if (GS(tsep->id->name) == ID_LS) { + FreestyleLineStyle *ls = (FreestyleLineStyle *)tsep->id; + mtex = ls->mtex; + } + else { + return; + } + + for (a = 0; a < MAX_MTEX; a++) { + if (a == te->index && mtex[a]) { + if (mtex[a]->tex) { + id_us_min(&mtex[a]->tex->id); + mtex[a]->tex = NULL; + } + } + } +} + +static void unlink_collection_cb(bContext *C, + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *tsep, + TreeStoreElem *tselem, + void *UNUSED(user_data)) +{ + Main *bmain = CTX_data_main(C); + Collection *collection = (Collection *)tselem->id; + + if (tsep) { + if (GS(tsep->id->name) == ID_OB) { + Object *ob = (Object *)tsep->id; + ob->instance_collection = NULL; + DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); + DEG_relations_tag_update(bmain); + } + else if (GS(tsep->id->name) == ID_GR) { + Collection *parent = (Collection *)tsep->id; + id_fake_user_set(&collection->id); + BKE_collection_child_remove(bmain, parent, collection); + DEG_id_tag_update(&parent->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + } + else if (GS(tsep->id->name) == ID_SCE) { + Scene *scene = (Scene *)tsep->id; + Collection *parent = BKE_collection_master(scene); + id_fake_user_set(&collection->id); + BKE_collection_child_remove(bmain, parent, collection); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + } + } +} + +static void unlink_object_cb(bContext *C, + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *tsep, + TreeStoreElem *tselem, + void *UNUSED(user_data)) +{ + Main *bmain = CTX_data_main(C); + Object *ob = (Object *)tselem->id; + + if (tsep) { + if (GS(tsep->id->name) == ID_GR) { + Collection *parent = (Collection *)tsep->id; + BKE_collection_object_remove(bmain, parent, ob, true); + DEG_id_tag_update(&parent->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + } + else if (GS(tsep->id->name) == ID_SCE) { + Scene *scene = (Scene *)tsep->id; + Collection *parent = BKE_collection_master(scene); + BKE_collection_object_remove(bmain, parent, ob, true); + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + } + } +} + +static void unlink_world_cb(bContext *UNUSED(C), + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *tsep, + TreeStoreElem *tselem, + void *UNUSED(user_data)) +{ + Scene *parscene = (Scene *)tsep->id; + World *wo = (World *)tselem->id; + + /* need to use parent scene not just scene, otherwise may end up getting wrong one */ + id_us_min(&wo->id); + parscene->world = NULL; +} + +static void outliner_do_libdata_operation(bContext *C, + ReportList *reports, + Scene *scene, + SpaceOutliner *soops, + ListBase *lb, + outliner_operation_cb operation_cb, + void *user_data) +{ + TreeElement *te; + TreeStoreElem *tselem; + + for (te = lb->first; te; te = te->next) { + tselem = TREESTORE(te); + if (tselem->flag & TSE_SELECTED) { + if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { + TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL; + operation_cb(C, reports, scene, te, tsep, tselem, user_data); + } + } + if (TSELEM_OPEN(tselem, soops)) { + outliner_do_libdata_operation( + C, reports, scene, soops, &te->subtree, operation_cb, user_data); + } + } } /* ******************************************** */ typedef enum eOutliner_PropSceneOps { - OL_SCENE_OP_DELETE = 1, + OL_SCENE_OP_DELETE = 1, } eOutliner_PropSceneOps; static const EnumPropertyItem prop_scene_op_types[] = { - {OL_SCENE_OP_DELETE, "DELETE", ICON_X, "Delete", ""}, - {0, NULL, 0, NULL, NULL}, + {OL_SCENE_OP_DELETE, "DELETE", ICON_X, "Delete", ""}, + {0, NULL, 0, NULL, NULL}, }; static bool outliner_do_scene_operation( - bContext *C, eOutliner_PropSceneOps event, ListBase *lb, - bool (*operation_cb)(bContext *, eOutliner_PropSceneOps, TreeElement *, TreeStoreElem *)) + bContext *C, + eOutliner_PropSceneOps event, + ListBase *lb, + bool (*operation_cb)(bContext *, eOutliner_PropSceneOps, TreeElement *, TreeStoreElem *)) { - TreeElement *te; - TreeStoreElem *tselem; - bool success = false; + TreeElement *te; + TreeStoreElem *tselem; + bool success = false; - for (te = lb->first; te; te = te->next) { - tselem = TREESTORE(te); - if (tselem->flag & TSE_SELECTED) { - if (operation_cb(C, event, te, tselem)) { - success = true; - } - } - } + for (te = lb->first; te; te = te->next) { + tselem = TREESTORE(te); + if (tselem->flag & TSE_SELECTED) { + if (operation_cb(C, event, te, tselem)) { + success = true; + } + } + } - return success; + return success; } -static bool scene_cb(bContext *C, eOutliner_PropSceneOps event, TreeElement *UNUSED(te), TreeStoreElem *tselem) +static bool scene_cb(bContext *C, + eOutliner_PropSceneOps event, + TreeElement *UNUSED(te), + TreeStoreElem *tselem) { - Scene *scene = (Scene *)tselem->id; + Scene *scene = (Scene *)tselem->id; - if (event == OL_SCENE_OP_DELETE) { - if (ED_scene_delete(C, CTX_data_main(C), CTX_wm_window(C), scene)) { - WM_event_add_notifier(C, NC_SCENE | NA_REMOVED, scene); - } - else { - return false; - } - } + if (event == OL_SCENE_OP_DELETE) { + if (ED_scene_delete(C, CTX_data_main(C), CTX_wm_window(C), scene)) { + WM_event_add_notifier(C, NC_SCENE | NA_REMOVED, scene); + } + else { + return false; + } + } - return true; + return true; } static int outliner_scene_operation_exec(bContext *C, wmOperator *op) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - const eOutliner_PropSceneOps event = RNA_enum_get(op->ptr, "type"); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + const eOutliner_PropSceneOps event = RNA_enum_get(op->ptr, "type"); - if (outliner_do_scene_operation(C, event, &soops->tree, scene_cb) == false) { - return OPERATOR_CANCELLED; - } + if (outliner_do_scene_operation(C, event, &soops->tree, scene_cb) == false) { + return OPERATOR_CANCELLED; + } - if (event == OL_SCENE_OP_DELETE) { - outliner_cleanup_tree(soops); - ED_undo_push(C, "Delete Scene(s)"); - } - else { - BLI_assert(0); - return OPERATOR_CANCELLED; - } + if (event == OL_SCENE_OP_DELETE) { + outliner_cleanup_tree(soops); + ED_undo_push(C, "Delete Scene(s)"); + } + else { + BLI_assert(0); + return OPERATOR_CANCELLED; + } - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_scene_operation(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Outliner Scene Operation"; - ot->idname = "OUTLINER_OT_scene_operation"; - ot->description = "Context menu for scene operations"; + /* identifiers */ + ot->name = "Outliner Scene Operation"; + ot->idname = "OUTLINER_OT_scene_operation"; + ot->description = "Context menu for scene operations"; - /* callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = outliner_scene_operation_exec; - ot->poll = ED_operator_outliner_active; + /* callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = outliner_scene_operation_exec; + ot->poll = ED_operator_outliner_active; - ot->flag = 0; + ot->flag = 0; - ot->prop = RNA_def_enum(ot->srna, "type", prop_scene_op_types, 0, "Scene Operation", ""); + ot->prop = RNA_def_enum(ot->srna, "type", prop_scene_op_types, 0, "Scene Operation", ""); } /* ******************************************** */ -static void object_select_cb( - bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob = (Object *)tselem->id; - Base *base = BKE_view_layer_base_find(view_layer, ob); - - if (base && ((base->flag & BASE_VISIBLE) != 0)) { - base->flag |= BASE_SELECTED; - } -} - -static void object_select_hierarchy_cb( - bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - /* Don't extend because this toggles, which is nice for Ctrl-Click but not for a menu item. - * it's especially confusing when multiple items are selected since some toggle on/off. */ - outliner_item_do_activate_from_tree_element(C, te, tselem, false, true); -} - -static void object_deselect_cb( - bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob = (Object *)tselem->id; - Base *base = BKE_view_layer_base_find(view_layer, ob); - - if (base) { - base->flag &= ~BASE_SELECTED; - } -} - -static void object_delete_cb( - bContext *C, ReportList *reports, Scene *scene, TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - Object *ob = (Object *)tselem->id; - if (ob) { - Main *bmain = CTX_data_main(C); - if (ob->id.tag & LIB_TAG_INDIRECT) { - BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", ob->id.name + 2); - return; - } - else if (BKE_library_ID_is_indirectly_used(bmain, ob) && - ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0) - { - BKE_reportf(reports, RPT_WARNING, - "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", - ob->id.name + 2, scene->id.name + 2); - return; - } - - // check also library later - if (ob == CTX_data_edit_object(C)) { - ED_object_editmode_exit(C, EM_FREEDATA); - } - ED_object_base_free_and_unlink(CTX_data_main(C), scene, ob); - /* leave for ED_outliner_id_unref to handle */ +static void object_select_cb(bContext *C, + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = (Object *)tselem->id; + Base *base = BKE_view_layer_base_find(view_layer, ob); + + if (base && ((base->flag & BASE_VISIBLE) != 0)) { + base->flag |= BASE_SELECTED; + } +} + +static void object_select_hierarchy_cb(bContext *C, + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *te, + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) +{ + /* Don't extend because this toggles, which is nice for Ctrl-Click but not for a menu item. + * it's especially confusing when multiple items are selected since some toggle on/off. */ + outliner_item_do_activate_from_tree_element(C, te, tselem, false, true); +} + +static void object_deselect_cb(bContext *C, + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = (Object *)tselem->id; + Base *base = BKE_view_layer_base_find(view_layer, ob); + + if (base) { + base->flag &= ~BASE_SELECTED; + } +} + +static void object_delete_cb(bContext *C, + ReportList *reports, + Scene *scene, + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) +{ + Object *ob = (Object *)tselem->id; + if (ob) { + Main *bmain = CTX_data_main(C); + if (ob->id.tag & LIB_TAG_INDIRECT) { + BKE_reportf( + reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", ob->id.name + 2); + return; + } + else if (BKE_library_ID_is_indirectly_used(bmain, ob) && ID_REAL_USERS(ob) <= 1 && + ID_EXTRA_USERS(ob) == 0) { + BKE_reportf(reports, + RPT_WARNING, + "Cannot delete object '%s' from scene '%s', indirectly used objects need at " + "least one user", + ob->id.name + 2, + scene->id.name + 2); + return; + } + + // check also library later + if (ob == CTX_data_edit_object(C)) { + ED_object_editmode_exit(C, EM_FREEDATA); + } + ED_object_base_free_and_unlink(CTX_data_main(C), scene, ob); + /* leave for ED_outliner_id_unref to handle */ #if 0 - te->directdata = NULL; - tselem->id = NULL; + te->directdata = NULL; + tselem->id = NULL; #endif - } + } } -static void id_local_cb( - bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void id_local_cb(bContext *C, + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) { - if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) { - Main *bmain = CTX_data_main(C); - /* if the ID type has no special local function, - * just clear the lib */ - if (id_make_local(bmain, tselem->id, false, false) == false) { - id_clear_lib_data(bmain, tselem->id); - } - else { - BKE_main_id_clear_newpoins(bmain); - } - } + if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) { + Main *bmain = CTX_data_main(C); + /* if the ID type has no special local function, + * just clear the lib */ + if (id_make_local(bmain, tselem->id, false, false) == false) { + id_clear_lib_data(bmain, tselem->id); + } + else { + BKE_main_id_clear_newpoins(bmain); + } + } } -static void id_static_override_cb( - bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void id_static_override_cb(bContext *C, + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) { - if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) { - Main *bmain = CTX_data_main(C); - ID *override_id = BKE_override_static_create_from_id(bmain, tselem->id); - if (override_id != NULL) { - BKE_main_id_clear_newpoins(bmain); - } - } + if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) { + Main *bmain = CTX_data_main(C); + ID *override_id = BKE_override_static_create_from_id(bmain, tselem->id); + if (override_id != NULL) { + BKE_main_id_clear_newpoins(bmain); + } + } } -static void id_fake_user_set_cb( - bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void id_fake_user_set_cb(bContext *UNUSED(C), + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) { - ID *id = tselem->id; + ID *id = tselem->id; - id_fake_user_set(id); + id_fake_user_set(id); } -static void id_fake_user_clear_cb( - bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void id_fake_user_clear_cb(bContext *UNUSED(C), + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) { - ID *id = tselem->id; + ID *id = tselem->id; - id_fake_user_clear(id); + id_fake_user_clear(id); } -static void id_select_linked_cb( - bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void id_select_linked_cb(bContext *C, + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) { - ID *id = tselem->id; + ID *id = tselem->id; - ED_object_select_linked_by_id(C, id); + ED_object_select_linked_by_id(C, id); } -static void singleuser_action_cb( - bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) +static void singleuser_action_cb(bContext *C, + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *tsep, + TreeStoreElem *tselem, + void *UNUSED(user_data)) { - ID *id = tselem->id; + ID *id = tselem->id; - if (id) { - IdAdtTemplate *iat = (IdAdtTemplate *)tsep->id; - PointerRNA ptr = {{NULL}}; - PropertyRNA *prop; + if (id) { + IdAdtTemplate *iat = (IdAdtTemplate *)tsep->id; + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop; - RNA_pointer_create(&iat->id, &RNA_AnimData, iat->adt, &ptr); - prop = RNA_struct_find_property(&ptr, "action"); + RNA_pointer_create(&iat->id, &RNA_AnimData, iat->adt, &ptr); + prop = RNA_struct_find_property(&ptr, "action"); - id_single_user(C, id, &ptr, prop); - } + id_single_user(C, id, &ptr, prop); + } } -static void singleuser_world_cb( - bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) +static void singleuser_world_cb(bContext *C, + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *tsep, + TreeStoreElem *tselem, + void *UNUSED(user_data)) { - ID *id = tselem->id; + ID *id = tselem->id; - /* need to use parent scene not just scene, otherwise may end up getting wrong one */ - if (id) { - Scene *parscene = (Scene *)tsep->id; - PointerRNA ptr = {{NULL}}; - PropertyRNA *prop; + /* need to use parent scene not just scene, otherwise may end up getting wrong one */ + if (id) { + Scene *parscene = (Scene *)tsep->id; + PointerRNA ptr = {{NULL}}; + PropertyRNA *prop; - RNA_id_pointer_create(&parscene->id, &ptr); - prop = RNA_struct_find_property(&ptr, "world"); + RNA_id_pointer_create(&parscene->id, &ptr); + prop = RNA_struct_find_property(&ptr, "world"); - id_single_user(C, id, &ptr, prop); - } + id_single_user(C, id, &ptr, prop); + } } /** * \param select_recurse: Set to false for operations which are already recursively operating on their children. */ -void outliner_do_object_operation_ex( - bContext *C, ReportList *reports, Scene *scene_act, SpaceOutliner *soops, ListBase *lb, - outliner_operation_cb operation_cb, void *user_data, bool select_recurse) -{ - TreeElement *te; - - for (te = lb->first; te; te = te->next) { - TreeStoreElem *tselem = TREESTORE(te); - bool select_handled = false; - if (tselem->flag & TSE_SELECTED) { - if (tselem->type == 0 && te->idcode == ID_OB) { - // when objects selected in other scenes... dunno if that should be allowed - Scene *scene_owner = (Scene *)outliner_search_back(soops, te, ID_SCE); - if (scene_owner && scene_act != scene_owner) { - WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), scene_owner); - } - /* important to use 'scene_owner' not scene_act else deleting objects can crash. - * only use 'scene_act' when 'scene_owner' is NULL, which can happen when the - * outliner isn't showing scenes: Visible Layer draw mode for eg. */ - operation_cb(C, reports, scene_owner ? scene_owner : scene_act, te, NULL, tselem, user_data); - select_handled = true; - } - } - if (TSELEM_OPEN(tselem, soops)) { - if ((select_handled == false) || select_recurse) { - outliner_do_object_operation_ex( - C, reports, scene_act, soops, &te->subtree, operation_cb, NULL, select_recurse); - } - } - } -} - -void outliner_do_object_operation( - bContext *C, ReportList *reports, Scene *scene_act, SpaceOutliner *soops, ListBase *lb, - outliner_operation_cb operation_cb) -{ - outliner_do_object_operation_ex(C, reports, scene_act, soops, lb, operation_cb, NULL, true); +void outliner_do_object_operation_ex(bContext *C, + ReportList *reports, + Scene *scene_act, + SpaceOutliner *soops, + ListBase *lb, + outliner_operation_cb operation_cb, + void *user_data, + bool select_recurse) +{ + TreeElement *te; + + for (te = lb->first; te; te = te->next) { + TreeStoreElem *tselem = TREESTORE(te); + bool select_handled = false; + if (tselem->flag & TSE_SELECTED) { + if (tselem->type == 0 && te->idcode == ID_OB) { + // when objects selected in other scenes... dunno if that should be allowed + Scene *scene_owner = (Scene *)outliner_search_back(soops, te, ID_SCE); + if (scene_owner && scene_act != scene_owner) { + WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), scene_owner); + } + /* important to use 'scene_owner' not scene_act else deleting objects can crash. + * only use 'scene_act' when 'scene_owner' is NULL, which can happen when the + * outliner isn't showing scenes: Visible Layer draw mode for eg. */ + operation_cb( + C, reports, scene_owner ? scene_owner : scene_act, te, NULL, tselem, user_data); + select_handled = true; + } + } + if (TSELEM_OPEN(tselem, soops)) { + if ((select_handled == false) || select_recurse) { + outliner_do_object_operation_ex( + C, reports, scene_act, soops, &te->subtree, operation_cb, NULL, select_recurse); + } + } + } +} + +void outliner_do_object_operation(bContext *C, + ReportList *reports, + Scene *scene_act, + SpaceOutliner *soops, + ListBase *lb, + outliner_operation_cb operation_cb) +{ + outliner_do_object_operation_ex(C, reports, scene_act, soops, lb, operation_cb, NULL, true); } /* ******************************************** */ -static void clear_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te), - TreeStoreElem *tselem, void *UNUSED(arg)) +static void clear_animdata_cb(int UNUSED(event), + TreeElement *UNUSED(te), + TreeStoreElem *tselem, + void *UNUSED(arg)) { - BKE_animdata_free(tselem->id, true); + BKE_animdata_free(tselem->id, true); } - -static void unlinkact_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te), - TreeStoreElem *tselem, void *UNUSED(arg)) +static void unlinkact_animdata_cb(int UNUSED(event), + TreeElement *UNUSED(te), + TreeStoreElem *tselem, + void *UNUSED(arg)) { - /* just set action to NULL */ - BKE_animdata_set_action(NULL, tselem->id, NULL); + /* just set action to NULL */ + BKE_animdata_set_action(NULL, tselem->id, NULL); } -static void cleardrivers_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te), - TreeStoreElem *tselem, void *UNUSED(arg)) +static void cleardrivers_animdata_cb(int UNUSED(event), + TreeElement *UNUSED(te), + TreeStoreElem *tselem, + void *UNUSED(arg)) { - IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id; + IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id; - /* just free drivers - stored as a list of F-Curves */ - free_fcurves(&iat->adt->drivers); + /* just free drivers - stored as a list of F-Curves */ + free_fcurves(&iat->adt->drivers); } -static void refreshdrivers_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te), - TreeStoreElem *tselem, void *UNUSED(arg)) +static void refreshdrivers_animdata_cb(int UNUSED(event), + TreeElement *UNUSED(te), + TreeStoreElem *tselem, + void *UNUSED(arg)) { - IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id; - FCurve *fcu; + IdAdtTemplate *iat = (IdAdtTemplate *)tselem->id; + FCurve *fcu; - /* loop over drivers, performing refresh (i.e. check graph_buttons.c and rna_fcurve.c for details) */ - for (fcu = iat->adt->drivers.first; fcu; fcu = fcu->next) { - fcu->flag &= ~FCURVE_DISABLED; + /* loop over drivers, performing refresh (i.e. check graph_buttons.c and rna_fcurve.c for details) */ + for (fcu = iat->adt->drivers.first; fcu; fcu = fcu->next) { + fcu->flag &= ~FCURVE_DISABLED; - if (fcu->driver) { - fcu->driver->flag &= ~DRIVER_FLAG_INVALID; - } - } + if (fcu->driver) { + fcu->driver->flag &= ~DRIVER_FLAG_INVALID; + } + } } /* --------------------------------- */ typedef enum eOutliner_PropDataOps { - OL_DOP_SELECT = 1, - OL_DOP_DESELECT, - OL_DOP_HIDE, - OL_DOP_UNHIDE, - OL_DOP_SELECT_LINKED, + OL_DOP_SELECT = 1, + OL_DOP_DESELECT, + OL_DOP_HIDE, + OL_DOP_UNHIDE, + OL_DOP_SELECT_LINKED, } eOutliner_PropDataOps; typedef enum eOutliner_PropConstraintOps { - OL_CONSTRAINTOP_ENABLE = 1, - OL_CONSTRAINTOP_DISABLE, - OL_CONSTRAINTOP_DELETE, + OL_CONSTRAINTOP_ENABLE = 1, + OL_CONSTRAINTOP_DISABLE, + OL_CONSTRAINTOP_DELETE, } eOutliner_PropConstraintOps; typedef enum eOutliner_PropModifierOps { - OL_MODIFIER_OP_TOGVIS = 1, - OL_MODIFIER_OP_TOGREN, - OL_MODIFIER_OP_DELETE, + OL_MODIFIER_OP_TOGVIS = 1, + OL_MODIFIER_OP_TOGREN, + OL_MODIFIER_OP_DELETE, } eOutliner_PropModifierOps; static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg)) { - bPoseChannel *pchan = (bPoseChannel *)te->directdata; + bPoseChannel *pchan = (bPoseChannel *)te->directdata; - if (event == OL_DOP_SELECT) { - pchan->bone->flag |= BONE_SELECTED; - } - else if (event == OL_DOP_DESELECT) { - pchan->bone->flag &= ~BONE_SELECTED; - } - else if (event == OL_DOP_HIDE) { - pchan->bone->flag |= BONE_HIDDEN_P; - pchan->bone->flag &= ~BONE_SELECTED; - } - else if (event == OL_DOP_UNHIDE) { - pchan->bone->flag &= ~BONE_HIDDEN_P; - } + if (event == OL_DOP_SELECT) { + pchan->bone->flag |= BONE_SELECTED; + } + else if (event == OL_DOP_DESELECT) { + pchan->bone->flag &= ~BONE_SELECTED; + } + else if (event == OL_DOP_HIDE) { + pchan->bone->flag |= BONE_HIDDEN_P; + pchan->bone->flag &= ~BONE_SELECTED; + } + else if (event == OL_DOP_UNHIDE) { + pchan->bone->flag &= ~BONE_HIDDEN_P; + } } static void bone_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg)) { - Bone *bone = (Bone *)te->directdata; + Bone *bone = (Bone *)te->directdata; - if (event == OL_DOP_SELECT) { - bone->flag |= BONE_SELECTED; - } - else if (event == OL_DOP_DESELECT) { - bone->flag &= ~BONE_SELECTED; - } - else if (event == OL_DOP_HIDE) { - bone->flag |= BONE_HIDDEN_P; - bone->flag &= ~BONE_SELECTED; - } - else if (event == OL_DOP_UNHIDE) { - bone->flag &= ~BONE_HIDDEN_P; - } + if (event == OL_DOP_SELECT) { + bone->flag |= BONE_SELECTED; + } + else if (event == OL_DOP_DESELECT) { + bone->flag &= ~BONE_SELECTED; + } + else if (event == OL_DOP_HIDE) { + bone->flag |= BONE_HIDDEN_P; + bone->flag &= ~BONE_SELECTED; + } + else if (event == OL_DOP_UNHIDE) { + bone->flag &= ~BONE_HIDDEN_P; + } } static void ebone_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg)) { - EditBone *ebone = (EditBone *)te->directdata; + EditBone *ebone = (EditBone *)te->directdata; - if (event == OL_DOP_SELECT) { - ebone->flag |= BONE_SELECTED; - } - else if (event == OL_DOP_DESELECT) { - ebone->flag &= ~BONE_SELECTED; - } - else if (event == OL_DOP_HIDE) { - ebone->flag |= BONE_HIDDEN_A; - ebone->flag &= ~BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL; - } - else if (event == OL_DOP_UNHIDE) { - ebone->flag &= ~BONE_HIDDEN_A; - } + if (event == OL_DOP_SELECT) { + ebone->flag |= BONE_SELECTED; + } + else if (event == OL_DOP_DESELECT) { + ebone->flag &= ~BONE_SELECTED; + } + else if (event == OL_DOP_HIDE) { + ebone->flag |= BONE_HIDDEN_A; + ebone->flag &= ~BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL; + } + else if (event == OL_DOP_UNHIDE) { + ebone->flag &= ~BONE_HIDDEN_A; + } } static void sequence_cb(int event, TreeElement *te, TreeStoreElem *tselem, void *scene_ptr) { - Sequence *seq = (Sequence *)te->directdata; - if (event == OL_DOP_SELECT) { - Scene *scene = (Scene *)scene_ptr; - Editing *ed = BKE_sequencer_editing_get(scene, false); - if (BLI_findindex(ed->seqbasep, seq) != -1) { - ED_sequencer_select_sequence_single(scene, seq, true); - } - } + Sequence *seq = (Sequence *)te->directdata; + if (event == OL_DOP_SELECT) { + Scene *scene = (Scene *)scene_ptr; + Editing *ed = BKE_sequencer_editing_get(scene, false); + if (BLI_findindex(ed->seqbasep, seq) != -1) { + ED_sequencer_select_sequence_single(scene, seq, true); + } + } - (void)tselem; + (void)tselem; } -static void gp_layer_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg)) +static void gp_layer_cb(int event, + TreeElement *te, + TreeStoreElem *UNUSED(tselem), + void *UNUSED(arg)) { - bGPDlayer *gpl = (bGPDlayer *)te->directdata; + bGPDlayer *gpl = (bGPDlayer *)te->directdata; - if (event == OL_DOP_SELECT) { - gpl->flag |= GP_LAYER_SELECT; - } - else if (event == OL_DOP_DESELECT) { - gpl->flag &= ~GP_LAYER_SELECT; - } - else if (event == OL_DOP_HIDE) { - gpl->flag |= GP_LAYER_HIDE; - } - else if (event == OL_DOP_UNHIDE) { - gpl->flag &= ~GP_LAYER_HIDE; - } + if (event == OL_DOP_SELECT) { + gpl->flag |= GP_LAYER_SELECT; + } + else if (event == OL_DOP_DESELECT) { + gpl->flag &= ~GP_LAYER_SELECT; + } + else if (event == OL_DOP_HIDE) { + gpl->flag |= GP_LAYER_HIDE; + } + else if (event == OL_DOP_UNHIDE) { + gpl->flag &= ~GP_LAYER_HIDE; + } } -static void data_select_linked_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v) +static void data_select_linked_cb(int event, + TreeElement *te, + TreeStoreElem *UNUSED(tselem), + void *C_v) { - if (event == OL_DOP_SELECT_LINKED) { - if (RNA_struct_is_ID(te->rnaptr.type)) { - bContext *C = (bContext *) C_v; - ID *id = te->rnaptr.data; + if (event == OL_DOP_SELECT_LINKED) { + if (RNA_struct_is_ID(te->rnaptr.type)) { + bContext *C = (bContext *)C_v; + ID *id = te->rnaptr.data; - ED_object_select_linked_by_id(C, id); - } - } + ED_object_select_linked_by_id(C, id); + } + } } static void constraint_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v) { - bContext *C = C_v; - Main *bmain = CTX_data_main(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - bConstraint *constraint = (bConstraint *)te->directdata; - Object *ob = (Object *)outliner_search_back(soops, te, ID_OB); - - if (event == OL_CONSTRAINTOP_ENABLE) { - constraint->flag &= ~CONSTRAINT_OFF; - ED_object_constraint_update(bmain, ob); - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); - } - else if (event == OL_CONSTRAINTOP_DISABLE) { - constraint->flag = CONSTRAINT_OFF; - ED_object_constraint_update(bmain, ob); - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); - } - else if (event == OL_CONSTRAINTOP_DELETE) { - ListBase *lb = NULL; - - if (TREESTORE(te->parent->parent)->type == TSE_POSE_CHANNEL) { - lb = &((bPoseChannel *)te->parent->parent->directdata)->constraints; - } - else { - lb = &ob->constraints; - } - - if (BKE_constraint_remove_ex(lb, ob, constraint, true)) { - /* there's no active constraint now, so make sure this is the case */ - BKE_constraints_active_set(&ob->constraints, NULL); - - /* needed to set the flags on posebones correctly */ - ED_object_constraint_update(bmain, ob); - - WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); - te->store_elem->flag &= ~TSE_SELECTED; - } - } + bContext *C = C_v; + Main *bmain = CTX_data_main(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + bConstraint *constraint = (bConstraint *)te->directdata; + Object *ob = (Object *)outliner_search_back(soops, te, ID_OB); + + if (event == OL_CONSTRAINTOP_ENABLE) { + constraint->flag &= ~CONSTRAINT_OFF; + ED_object_constraint_update(bmain, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); + } + else if (event == OL_CONSTRAINTOP_DISABLE) { + constraint->flag = CONSTRAINT_OFF; + ED_object_constraint_update(bmain, ob); + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); + } + else if (event == OL_CONSTRAINTOP_DELETE) { + ListBase *lb = NULL; + + if (TREESTORE(te->parent->parent)->type == TSE_POSE_CHANNEL) { + lb = &((bPoseChannel *)te->parent->parent->directdata)->constraints; + } + else { + lb = &ob->constraints; + } + + if (BKE_constraint_remove_ex(lb, ob, constraint, true)) { + /* there's no active constraint now, so make sure this is the case */ + BKE_constraints_active_set(&ob->constraints, NULL); + + /* needed to set the flags on posebones correctly */ + ED_object_constraint_update(bmain, ob); + + WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, ob); + te->store_elem->flag &= ~TSE_SELECTED; + } + } } static void modifier_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *Carg) { - bContext *C = (bContext *)Carg; - Main *bmain = CTX_data_main(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - ModifierData *md = (ModifierData *)te->directdata; - Object *ob = (Object *)outliner_search_back(soops, te, ID_OB); - - if (event == OL_MODIFIER_OP_TOGVIS) { - md->mode ^= eModifierMode_Realtime; - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - } - else if (event == OL_MODIFIER_OP_TOGREN) { - md->mode ^= eModifierMode_Render; - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); - } - else if (event == OL_MODIFIER_OP_DELETE) { - ED_object_modifier_remove(NULL, bmain, ob, md); - WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER | NA_REMOVED, ob); - te->store_elem->flag &= ~TSE_SELECTED; - } -} - -static void outliner_do_data_operation(SpaceOutliner *soops, int type, int event, ListBase *lb, - void (*operation_cb)(int, TreeElement *, TreeStoreElem *, void *), - void *arg) -{ - TreeElement *te; - TreeStoreElem *tselem; - - for (te = lb->first; te; te = te->next) { - tselem = TREESTORE(te); - if (tselem->flag & TSE_SELECTED) { - if (tselem->type == type) { - operation_cb(event, te, tselem, arg); - } - } - if (TSELEM_OPEN(tselem, soops)) { - outliner_do_data_operation(soops, type, event, &te->subtree, operation_cb, arg); - } - } + bContext *C = (bContext *)Carg; + Main *bmain = CTX_data_main(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + ModifierData *md = (ModifierData *)te->directdata; + Object *ob = (Object *)outliner_search_back(soops, te, ID_OB); + + if (event == OL_MODIFIER_OP_TOGVIS) { + md->mode ^= eModifierMode_Realtime; + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + } + else if (event == OL_MODIFIER_OP_TOGREN) { + md->mode ^= eModifierMode_Render; + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); + } + else if (event == OL_MODIFIER_OP_DELETE) { + ED_object_modifier_remove(NULL, bmain, ob, md); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER | NA_REMOVED, ob); + te->store_elem->flag &= ~TSE_SELECTED; + } +} + +static void outliner_do_data_operation( + SpaceOutliner *soops, + int type, + int event, + ListBase *lb, + void (*operation_cb)(int, TreeElement *, TreeStoreElem *, void *), + void *arg) +{ + TreeElement *te; + TreeStoreElem *tselem; + + for (te = lb->first; te; te = te->next) { + tselem = TREESTORE(te); + if (tselem->flag & TSE_SELECTED) { + if (tselem->type == type) { + operation_cb(event, te, tselem, arg); + } + } + if (TSELEM_OPEN(tselem, soops)) { + outliner_do_data_operation(soops, type, event, &te->subtree, operation_cb, arg); + } + } } static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *scene, Base *base) { - Base *child_base, *base_next; - Object *parent; - ViewLayer *view_layer = CTX_data_view_layer(C); - - if (!base) { - return NULL; - } - - for (child_base = view_layer->object_bases.first; child_base; child_base = base_next) { - base_next = child_base->next; - for (parent = child_base->object->parent; parent && (parent != base->object); parent = parent->parent) { - /* pass */ - } - if (parent) { - base_next = outline_delete_hierarchy(C, reports, scene, child_base); - } - } - - base_next = base->next; - - Main *bmain = CTX_data_main(C); - if (base->object->id.tag & LIB_TAG_INDIRECT) { - BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2); - return base_next; - } - else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && - ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) - { - BKE_reportf(reports, RPT_WARNING, - "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", - base->object->id.name + 2, scene->id.name + 2); - return base_next; - } - ED_object_base_free_and_unlink(CTX_data_main(C), scene, base->object); - return base_next; -} - -static void object_delete_hierarchy_cb( - bContext *C, ReportList *reports, Scene *scene, - TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - ViewLayer *view_layer = CTX_data_view_layer(C); - Base *base = (Base *)te->directdata; - Object *obedit = CTX_data_edit_object(C); - - if (!base) { - base = BKE_view_layer_base_find(view_layer, (Object *)tselem->id); - } - if (base) { - /* Check also library later. */ - for (; obedit && (obedit != base->object); obedit = obedit->parent) { - /* pass */ - } - if (obedit == base->object) { - ED_object_editmode_exit(C, EM_FREEDATA); - } - - outline_delete_hierarchy(C, reports, scene, base); - /* leave for ED_outliner_id_unref to handle */ + Base *child_base, *base_next; + Object *parent; + ViewLayer *view_layer = CTX_data_view_layer(C); + + if (!base) { + return NULL; + } + + for (child_base = view_layer->object_bases.first; child_base; child_base = base_next) { + base_next = child_base->next; + for (parent = child_base->object->parent; parent && (parent != base->object); + parent = parent->parent) { + /* pass */ + } + if (parent) { + base_next = outline_delete_hierarchy(C, reports, scene, child_base); + } + } + + base_next = base->next; + + Main *bmain = CTX_data_main(C); + if (base->object->id.tag & LIB_TAG_INDIRECT) { + BKE_reportf(reports, + RPT_WARNING, + "Cannot delete indirectly linked object '%s'", + base->object->id.name + 2); + return base_next; + } + else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && + ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) { + BKE_reportf(reports, + RPT_WARNING, + "Cannot delete object '%s' from scene '%s', indirectly used objects need at least " + "one user", + base->object->id.name + 2, + scene->id.name + 2); + return base_next; + } + ED_object_base_free_and_unlink(CTX_data_main(C), scene, base->object); + return base_next; +} + +static void object_delete_hierarchy_cb(bContext *C, + ReportList *reports, + Scene *scene, + TreeElement *te, + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + Base *base = (Base *)te->directdata; + Object *obedit = CTX_data_edit_object(C); + + if (!base) { + base = BKE_view_layer_base_find(view_layer, (Object *)tselem->id); + } + if (base) { + /* Check also library later. */ + for (; obedit && (obedit != base->object); obedit = obedit->parent) { + /* pass */ + } + if (obedit == base->object) { + ED_object_editmode_exit(C, EM_FREEDATA); + } + + outline_delete_hierarchy(C, reports, scene, base); + /* leave for ED_outliner_id_unref to handle */ #if 0 - te->directdata = NULL; - tselem->id = NULL; + te->directdata = NULL; + tselem->id = NULL; #endif - } + } - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); } static Base *outline_batch_delete_hierarchy( - ReportList *reports, Main *bmain, ViewLayer *view_layer, Scene *scene, Base *base) -{ - Base *child_base, *base_next; - Object *object, *parent; - - if (!base) { - return NULL; - } - - object = base->object; - for (child_base = view_layer->object_bases.first; child_base; child_base = base_next) { - base_next = child_base->next; - for (parent = child_base->object->parent; parent && (parent != object); parent = parent->parent) { - /* pass */ - } - if (parent) { - base_next = outline_batch_delete_hierarchy(reports, bmain, view_layer, scene, child_base); - } - } - - base_next = base->next; - - if (object->id.tag & LIB_TAG_INDIRECT) { - BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2); - return base_next; - } - else if (BKE_library_ID_is_indirectly_used(bmain, object) && - ID_REAL_USERS(object) <= 1 && ID_EXTRA_USERS(object) == 0) - { - BKE_reportf(reports, RPT_WARNING, - "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", - object->id.name + 2, scene->id.name + 2); - return base_next; - } - - DEG_id_tag_update_ex(bmain, &object->id, ID_RECALC_BASE_FLAGS); - BKE_scene_collections_object_remove(bmain, scene, object, false); - - if (object->id.us == 0) { - object->id.tag |= LIB_TAG_DOIT; - } - - return base_next; -} - -static void object_batch_delete_hierarchy_cb( - bContext *C, ReportList *reports, Scene *scene, - TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) -{ - ViewLayer *view_layer = CTX_data_view_layer(C); - Base *base = (Base *)te->directdata; - Object *obedit = CTX_data_edit_object(C); - - if (!base) { - base = BKE_view_layer_base_find(view_layer, (Object *)tselem->id); - } - if (base) { - /* Check also library later. */ - for (; obedit && (obedit != base->object); obedit = obedit->parent) { - /* pass */ - } - if (obedit == base->object) { - ED_object_editmode_exit(C, EM_FREEDATA); - } - - outline_batch_delete_hierarchy(reports, CTX_data_main(C), view_layer, scene, base); - /* leave for ED_outliner_id_unref to handle */ + ReportList *reports, Main *bmain, ViewLayer *view_layer, Scene *scene, Base *base) +{ + Base *child_base, *base_next; + Object *object, *parent; + + if (!base) { + return NULL; + } + + object = base->object; + for (child_base = view_layer->object_bases.first; child_base; child_base = base_next) { + base_next = child_base->next; + for (parent = child_base->object->parent; parent && (parent != object); + parent = parent->parent) { + /* pass */ + } + if (parent) { + base_next = outline_batch_delete_hierarchy(reports, bmain, view_layer, scene, child_base); + } + } + + base_next = base->next; + + if (object->id.tag & LIB_TAG_INDIRECT) { + BKE_reportf(reports, + RPT_WARNING, + "Cannot delete indirectly linked object '%s'", + base->object->id.name + 2); + return base_next; + } + else if (BKE_library_ID_is_indirectly_used(bmain, object) && ID_REAL_USERS(object) <= 1 && + ID_EXTRA_USERS(object) == 0) { + BKE_reportf(reports, + RPT_WARNING, + "Cannot delete object '%s' from scene '%s', indirectly used objects need at least " + "one user", + object->id.name + 2, + scene->id.name + 2); + return base_next; + } + + DEG_id_tag_update_ex(bmain, &object->id, ID_RECALC_BASE_FLAGS); + BKE_scene_collections_object_remove(bmain, scene, object, false); + + if (object->id.us == 0) { + object->id.tag |= LIB_TAG_DOIT; + } + + return base_next; +} + +static void object_batch_delete_hierarchy_cb(bContext *C, + ReportList *reports, + Scene *scene, + TreeElement *te, + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) +{ + ViewLayer *view_layer = CTX_data_view_layer(C); + Base *base = (Base *)te->directdata; + Object *obedit = CTX_data_edit_object(C); + + if (!base) { + base = BKE_view_layer_base_find(view_layer, (Object *)tselem->id); + } + if (base) { + /* Check also library later. */ + for (; obedit && (obedit != base->object); obedit = obedit->parent) { + /* pass */ + } + if (obedit == base->object) { + ED_object_editmode_exit(C, EM_FREEDATA); + } + + outline_batch_delete_hierarchy(reports, CTX_data_main(C), view_layer, scene, base); + /* leave for ED_outliner_id_unref to handle */ #if 0 - te->directdata = NULL; - tselem->id = NULL; + te->directdata = NULL; + tselem->id = NULL; #endif - } + } } /* **************************************** */ enum { - OL_OP_SELECT = 1, - OL_OP_DESELECT, - OL_OP_SELECT_HIERARCHY, - OL_OP_DELETE, - OL_OP_DELETE_HIERARCHY, - OL_OP_REMAP, - OL_OP_LOCALIZED, /* disabled, see below */ - OL_OP_TOGVIS, - OL_OP_TOGSEL, - OL_OP_TOGREN, - OL_OP_RENAME, - OL_OP_OBJECT_MODE_ENTER, - OL_OP_OBJECT_MODE_EXIT, + OL_OP_SELECT = 1, + OL_OP_DESELECT, + OL_OP_SELECT_HIERARCHY, + OL_OP_DELETE, + OL_OP_DELETE_HIERARCHY, + OL_OP_REMAP, + OL_OP_LOCALIZED, /* disabled, see below */ + OL_OP_TOGVIS, + OL_OP_TOGSEL, + OL_OP_TOGREN, + OL_OP_RENAME, + OL_OP_OBJECT_MODE_ENTER, + OL_OP_OBJECT_MODE_EXIT, }; static const EnumPropertyItem prop_object_op_types[] = { - {OL_OP_SELECT, "SELECT", ICON_RESTRICT_SELECT_OFF, "Select", ""}, - {OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""}, - {OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""}, - {OL_OP_DELETE, "DELETE", ICON_X, "Delete", ""}, - {OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""}, - {OL_OP_REMAP, "REMAP", 0, "Remap Users", - "Make all users of selected data-blocks to use instead a new chosen one"}, - {OL_OP_RENAME, "RENAME", 0, "Rename", ""}, - {OL_OP_OBJECT_MODE_ENTER, "OBJECT_MODE_ENTER", 0, "Enter Mode", ""}, - {OL_OP_OBJECT_MODE_EXIT, "OBJECT_MODE_EXIT", 0, "Exit Mode", ""}, - {0, NULL, 0, NULL, NULL}, + {OL_OP_SELECT, "SELECT", ICON_RESTRICT_SELECT_OFF, "Select", ""}, + {OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""}, + {OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""}, + {OL_OP_DELETE, "DELETE", ICON_X, "Delete", ""}, + {OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""}, + {OL_OP_REMAP, + "REMAP", + 0, + "Remap Users", + "Make all users of selected data-blocks to use instead a new chosen one"}, + {OL_OP_RENAME, "RENAME", 0, "Rename", ""}, + {OL_OP_OBJECT_MODE_ENTER, "OBJECT_MODE_ENTER", 0, "Enter Mode", ""}, + {OL_OP_OBJECT_MODE_EXIT, "OBJECT_MODE_EXIT", 0, "Exit Mode", ""}, + {0, NULL, 0, NULL, NULL}, }; static int outliner_object_operation_exec(bContext *C, wmOperator *op) { - struct wmMsgBus *mbus = CTX_wm_message_bus(C); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - wmWindow *win = CTX_wm_window(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - int event; - const char *str = NULL; - - /* check for invalid states */ - if (soops == NULL) { - return OPERATOR_CANCELLED; - } - - event = RNA_enum_get(op->ptr, "type"); - - if (event == OL_OP_SELECT) { - Scene *sce = scene; // to be able to delete, scenes are set... - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_select_cb); - if (scene != sce) { - WM_window_set_active_scene(bmain, C, win, sce); - } - - str = "Select Objects"; - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } - else if (event == OL_OP_SELECT_HIERARCHY) { - Scene *sce = scene; // to be able to delete, scenes are set... - outliner_do_object_operation_ex( - C, op->reports, scene, soops, &soops->tree, object_select_hierarchy_cb, NULL, false); - if (scene != sce) { - WM_window_set_active_scene(bmain, C, win, sce); - } - str = "Select Object Hierarchy"; - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } - else if (event == OL_OP_DESELECT) { - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_deselect_cb); - str = "Deselect Objects"; - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - } - else if (event == OL_OP_DELETE) { - ViewLayer *view_layer = CTX_data_view_layer(C); - const Base *basact_prev = BASACT(view_layer); - - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_delete_cb); - - /* XXX: tree management normally happens from draw_outliner(), but when - * you're clicking to fast on Delete object from context menu in - * outliner several mouse events can be handled in one cycle without - * handling notifiers/redraw which leads to deleting the same object twice. - * cleanup tree here to prevent such cases. */ - outliner_cleanup_tree(soops); - - DEG_relations_tag_update(bmain); - str = "Delete Objects"; - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - if (basact_prev != BASACT(view_layer)) { - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); - } - } - else if (event == OL_OP_DELETE_HIERARCHY) { - ViewLayer *view_layer = CTX_data_view_layer(C); - const Base *basact_prev = BASACT(view_layer); - - /* Keeping old 'safe and slow' code for a bit (new one enabled on 28/01/2019). */ - if (G.debug_value == 666) { - outliner_do_object_operation_ex( - C, op->reports, scene, soops, &soops->tree, object_delete_hierarchy_cb, NULL, false); - } - else { - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - - outliner_do_object_operation_ex( - C, op->reports, scene, soops, &soops->tree, object_batch_delete_hierarchy_cb, NULL, false); - - BKE_id_multi_tagged_delete(bmain); - } - - /* XXX: See OL_OP_DELETE comment above. */ - outliner_cleanup_tree(soops); - - DEG_relations_tag_update(bmain); - str = "Delete Object Hierarchy"; - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - if (basact_prev != BASACT(view_layer)) { - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); - } - } - else if (event == OL_OP_REMAP) { - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL); - str = "Remap ID"; - } - else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */ - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb); - str = "Localized Objects"; - } - else if (event == OL_OP_RENAME) { - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb); - str = "Rename Object"; - } - else if (event == OL_OP_OBJECT_MODE_ENTER) { - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_object_mode_enter_cb); - str = "Enter Current Mode"; - } - else if (event == OL_OP_OBJECT_MODE_EXIT) { - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_object_mode_exit_cb); - str = "Exit Current Mode"; - } - else { - BLI_assert(0); - return OPERATOR_CANCELLED; - } - - ED_undo_push(C, str); - - return OPERATOR_FINISHED; + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + wmWindow *win = CTX_wm_window(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + int event; + const char *str = NULL; + + /* check for invalid states */ + if (soops == NULL) { + return OPERATOR_CANCELLED; + } + + event = RNA_enum_get(op->ptr, "type"); + + if (event == OL_OP_SELECT) { + Scene *sce = scene; // to be able to delete, scenes are set... + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_select_cb); + if (scene != sce) { + WM_window_set_active_scene(bmain, C, win, sce); + } + + str = "Select Objects"; + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + } + else if (event == OL_OP_SELECT_HIERARCHY) { + Scene *sce = scene; // to be able to delete, scenes are set... + outliner_do_object_operation_ex( + C, op->reports, scene, soops, &soops->tree, object_select_hierarchy_cb, NULL, false); + if (scene != sce) { + WM_window_set_active_scene(bmain, C, win, sce); + } + str = "Select Object Hierarchy"; + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + } + else if (event == OL_OP_DESELECT) { + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_deselect_cb); + str = "Deselect Objects"; + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + } + else if (event == OL_OP_DELETE) { + ViewLayer *view_layer = CTX_data_view_layer(C); + const Base *basact_prev = BASACT(view_layer); + + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_delete_cb); + + /* XXX: tree management normally happens from draw_outliner(), but when + * you're clicking to fast on Delete object from context menu in + * outliner several mouse events can be handled in one cycle without + * handling notifiers/redraw which leads to deleting the same object twice. + * cleanup tree here to prevent such cases. */ + outliner_cleanup_tree(soops); + + DEG_relations_tag_update(bmain); + str = "Delete Objects"; + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + if (basact_prev != BASACT(view_layer)) { + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); + } + } + else if (event == OL_OP_DELETE_HIERARCHY) { + ViewLayer *view_layer = CTX_data_view_layer(C); + const Base *basact_prev = BASACT(view_layer); + + /* Keeping old 'safe and slow' code for a bit (new one enabled on 28/01/2019). */ + if (G.debug_value == 666) { + outliner_do_object_operation_ex( + C, op->reports, scene, soops, &soops->tree, object_delete_hierarchy_cb, NULL, false); + } + else { + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + + outliner_do_object_operation_ex(C, + op->reports, + scene, + soops, + &soops->tree, + object_batch_delete_hierarchy_cb, + NULL, + false); + + BKE_id_multi_tagged_delete(bmain); + } + + /* XXX: See OL_OP_DELETE comment above. */ + outliner_cleanup_tree(soops); + + DEG_relations_tag_update(bmain); + str = "Delete Object Hierarchy"; + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + if (basact_prev != BASACT(view_layer)) { + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); + } + } + else if (event == OL_OP_REMAP) { + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL); + str = "Remap ID"; + } + else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */ + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb); + str = "Localized Objects"; + } + else if (event == OL_OP_RENAME) { + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb); + str = "Rename Object"; + } + else if (event == OL_OP_OBJECT_MODE_ENTER) { + outliner_do_object_operation( + C, op->reports, scene, soops, &soops->tree, item_object_mode_enter_cb); + str = "Enter Current Mode"; + } + else if (event == OL_OP_OBJECT_MODE_EXIT) { + outliner_do_object_operation( + C, op->reports, scene, soops, &soops->tree, item_object_mode_exit_cb); + str = "Exit Current Mode"; + } + else { + BLI_assert(0); + return OPERATOR_CANCELLED; + } + + ED_undo_push(C, str); + + return OPERATOR_FINISHED; } - void OUTLINER_OT_object_operation(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Outliner Object Operation"; - ot->idname = "OUTLINER_OT_object_operation"; + /* identifiers */ + ot->name = "Outliner Object Operation"; + ot->idname = "OUTLINER_OT_object_operation"; - /* callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = outliner_object_operation_exec; - ot->poll = ED_operator_outliner_active; + /* callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = outliner_object_operation_exec; + ot->poll = ED_operator_outliner_active; - ot->flag = 0; + ot->flag = 0; - ot->prop = RNA_def_enum(ot->srna, "type", prop_object_op_types, 0, "Object Operation", ""); + ot->prop = RNA_def_enum(ot->srna, "type", prop_object_op_types, 0, "Object Operation", ""); } /* **************************************** */ typedef enum eOutlinerIdOpTypes { - OUTLINER_IDOP_INVALID = 0, + OUTLINER_IDOP_INVALID = 0, - OUTLINER_IDOP_UNLINK, - OUTLINER_IDOP_LOCAL, - OUTLINER_IDOP_STATIC_OVERRIDE, - OUTLINER_IDOP_SINGLE, - OUTLINER_IDOP_DELETE, - OUTLINER_IDOP_REMAP, + OUTLINER_IDOP_UNLINK, + OUTLINER_IDOP_LOCAL, + OUTLINER_IDOP_STATIC_OVERRIDE, + OUTLINER_IDOP_SINGLE, + OUTLINER_IDOP_DELETE, + OUTLINER_IDOP_REMAP, - OUTLINER_IDOP_COPY, - OUTLINER_IDOP_PASTE, + OUTLINER_IDOP_COPY, + OUTLINER_IDOP_PASTE, - OUTLINER_IDOP_FAKE_ADD, - OUTLINER_IDOP_FAKE_CLEAR, - OUTLINER_IDOP_RENAME, + OUTLINER_IDOP_FAKE_ADD, + OUTLINER_IDOP_FAKE_CLEAR, + OUTLINER_IDOP_RENAME, - OUTLINER_IDOP_SELECT_LINKED, + OUTLINER_IDOP_SELECT_LINKED, } eOutlinerIdOpTypes; // TODO: implement support for changing the ID-block used static const EnumPropertyItem prop_id_op_types[] = { - {OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""}, - {OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""}, - {OUTLINER_IDOP_STATIC_OVERRIDE, "STATIC_OVERRIDE", 0, "Add Static Override", - "Add a local static override of this data-block"}, - {OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""}, - {OUTLINER_IDOP_DELETE, "DELETE", ICON_X, "Delete", ""}, - {OUTLINER_IDOP_REMAP, "REMAP", 0, "Remap Users", - "Make all users of selected data-blocks to use instead current (clicked) one"}, - {0, "", 0, NULL, NULL}, - {OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""}, - {OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""}, - {0, "", 0, NULL, NULL}, - {OUTLINER_IDOP_FAKE_ADD, "ADD_FAKE", 0, "Add Fake User", - "Ensure data-block gets saved even if it isn't in use (e.g. for motion and material libraries)"}, - {OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""}, - {OUTLINER_IDOP_RENAME, "RENAME", 0, "Rename", ""}, - {OUTLINER_IDOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""}, - {0, NULL, 0, NULL, NULL}, + {OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""}, + {OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""}, + {OUTLINER_IDOP_STATIC_OVERRIDE, + "STATIC_OVERRIDE", + 0, + "Add Static Override", + "Add a local static override of this data-block"}, + {OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""}, + {OUTLINER_IDOP_DELETE, "DELETE", ICON_X, "Delete", ""}, + {OUTLINER_IDOP_REMAP, + "REMAP", + 0, + "Remap Users", + "Make all users of selected data-blocks to use instead current (clicked) one"}, + {0, "", 0, NULL, NULL}, + {OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""}, + {OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""}, + {0, "", 0, NULL, NULL}, + {OUTLINER_IDOP_FAKE_ADD, + "ADD_FAKE", + 0, + "Add Fake User", + "Ensure data-block gets saved even if it isn't in use (e.g. for motion and material " + "libraries)"}, + {OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""}, + {OUTLINER_IDOP_RENAME, "RENAME", 0, "Rename", ""}, + {OUTLINER_IDOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""}, + {0, NULL, 0, NULL, NULL}, }; -static const EnumPropertyItem *outliner_id_operation_itemf( - bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +static const EnumPropertyItem *outliner_id_operation_itemf(bContext *UNUSED(C), + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) { - if (BKE_override_static_is_enabled()) { - *r_free = false; - return prop_id_op_types; - } + if (BKE_override_static_is_enabled()) { + *r_free = false; + return prop_id_op_types; + } - EnumPropertyItem *items = NULL; - int totitem = 0; + EnumPropertyItem *items = NULL; + int totitem = 0; - for (const EnumPropertyItem *it = prop_id_op_types; it->identifier != NULL; it++) { - if (it->value == OUTLINER_IDOP_STATIC_OVERRIDE) { - continue; - } - RNA_enum_item_add(&items, &totitem, it); - } - RNA_enum_item_end(&items, &totitem); - *r_free = true; + for (const EnumPropertyItem *it = prop_id_op_types; it->identifier != NULL; it++) { + if (it->value == OUTLINER_IDOP_STATIC_OVERRIDE) { + continue; + } + RNA_enum_item_add(&items, &totitem, it); + } + RNA_enum_item_end(&items, &totitem); + *r_free = true; - return items; + return items; } static int outliner_id_operation_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - eOutlinerIdOpTypes event; - - /* check for invalid states */ - if (soops == NULL) { - return OPERATOR_CANCELLED; - } - - set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); - - event = RNA_enum_get(op->ptr, "type"); - - switch (event) { - case OUTLINER_IDOP_UNLINK: - { - /* unlink datablock from its parent */ - if (objectlevel) { - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_object_cb, NULL); - - WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL); - ED_undo_push(C, "Unlink Object"); - break; - } - - switch (idlevel) { - case ID_AC: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_action_cb, NULL); - - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); - ED_undo_push(C, "Unlink action"); - break; - case ID_MA: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_material_cb, NULL); - - WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL); - ED_undo_push(C, "Unlink material"); - break; - case ID_TE: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_texture_cb, NULL); - - WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL); - ED_undo_push(C, "Unlink texture"); - break; - case ID_WO: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_world_cb, NULL); - - WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL); - ED_undo_push(C, "Unlink world"); - break; - case ID_GR: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_collection_cb, NULL); - - WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL); - ED_undo_push(C, "Unlink Collection"); - break; - default: - BKE_report(op->reports, RPT_WARNING, "Not yet implemented"); - break; - } - break; - } - case OUTLINER_IDOP_LOCAL: - { - /* make local */ - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL); - ED_undo_push(C, "Localized Data"); - break; - } - case OUTLINER_IDOP_STATIC_OVERRIDE: - { - if (BKE_override_static_is_enabled()) { - /* make local */ - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_static_override_cb, NULL); - ED_undo_push(C, "Overridden Data"); - } - break; - } - case OUTLINER_IDOP_SINGLE: - { - /* make single user */ - switch (idlevel) { - case ID_AC: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, singleuser_action_cb, NULL); - - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); - ED_undo_push(C, "Single-User Action"); - break; - - case ID_WO: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, singleuser_world_cb, NULL); - - WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL); - ED_undo_push(C, "Single-User World"); - break; - - default: - BKE_report(op->reports, RPT_WARNING, "Not yet implemented"); - break; - } - break; - } - case OUTLINER_IDOP_DELETE: - { - if (idlevel > 0) { - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL); - ED_undo_push(C, "Delete"); - } - break; - } - case OUTLINER_IDOP_REMAP: - { - if (idlevel > 0) { - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL); - ED_undo_push(C, "Remap"); - } - break; - } - case OUTLINER_IDOP_COPY: - { - WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, NULL); - break; - } - case OUTLINER_IDOP_PASTE: - { - WM_operator_name_call(C, "OUTLINER_OT_id_paste", WM_OP_INVOKE_DEFAULT, NULL); - ED_undo_push(C, "Paste"); - break; - } - case OUTLINER_IDOP_FAKE_ADD: - { - /* set fake user */ - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_fake_user_set_cb, NULL); - - WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); - ED_undo_push(C, "Add Fake User"); - break; - } - case OUTLINER_IDOP_FAKE_CLEAR: - { - /* clear fake user */ - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_fake_user_clear_cb, NULL); - - WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); - ED_undo_push(C, "Clear Fake User"); - break; - } - case OUTLINER_IDOP_RENAME: - { - /* rename */ - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL); - - WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); - ED_undo_push(C, "Rename"); - break; - } - case OUTLINER_IDOP_SELECT_LINKED: - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_select_linked_cb, NULL); - ED_undo_push(C, "Select"); - break; - - default: - // invalid - unhandled - break; - } - - /* wrong notifier still... */ - WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); - - // XXX: this is just so that outliner is always up to date - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; + eOutlinerIdOpTypes event; + + /* check for invalid states */ + if (soops == NULL) { + return OPERATOR_CANCELLED; + } + + set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + + event = RNA_enum_get(op->ptr, "type"); + + switch (event) { + case OUTLINER_IDOP_UNLINK: { + /* unlink datablock from its parent */ + if (objectlevel) { + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, unlink_object_cb, NULL); + + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL); + ED_undo_push(C, "Unlink Object"); + break; + } + + switch (idlevel) { + case ID_AC: + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, unlink_action_cb, NULL); + + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); + ED_undo_push(C, "Unlink action"); + break; + case ID_MA: + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, unlink_material_cb, NULL); + + WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL); + ED_undo_push(C, "Unlink material"); + break; + case ID_TE: + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, unlink_texture_cb, NULL); + + WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL); + ED_undo_push(C, "Unlink texture"); + break; + case ID_WO: + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, unlink_world_cb, NULL); + + WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL); + ED_undo_push(C, "Unlink world"); + break; + case ID_GR: + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, unlink_collection_cb, NULL); + + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL); + ED_undo_push(C, "Unlink Collection"); + break; + default: + BKE_report(op->reports, RPT_WARNING, "Not yet implemented"); + break; + } + break; + } + case OUTLINER_IDOP_LOCAL: { + /* make local */ + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL); + ED_undo_push(C, "Localized Data"); + break; + } + case OUTLINER_IDOP_STATIC_OVERRIDE: { + if (BKE_override_static_is_enabled()) { + /* make local */ + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, id_static_override_cb, NULL); + ED_undo_push(C, "Overridden Data"); + } + break; + } + case OUTLINER_IDOP_SINGLE: { + /* make single user */ + switch (idlevel) { + case ID_AC: + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, singleuser_action_cb, NULL); + + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); + ED_undo_push(C, "Single-User Action"); + break; + + case ID_WO: + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, singleuser_world_cb, NULL); + + WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL); + ED_undo_push(C, "Single-User World"); + break; + + default: + BKE_report(op->reports, RPT_WARNING, "Not yet implemented"); + break; + } + break; + } + case OUTLINER_IDOP_DELETE: { + if (idlevel > 0) { + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL); + ED_undo_push(C, "Delete"); + } + break; + } + case OUTLINER_IDOP_REMAP: { + if (idlevel > 0) { + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL); + ED_undo_push(C, "Remap"); + } + break; + } + case OUTLINER_IDOP_COPY: { + WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, NULL); + break; + } + case OUTLINER_IDOP_PASTE: { + WM_operator_name_call(C, "OUTLINER_OT_id_paste", WM_OP_INVOKE_DEFAULT, NULL); + ED_undo_push(C, "Paste"); + break; + } + case OUTLINER_IDOP_FAKE_ADD: { + /* set fake user */ + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, id_fake_user_set_cb, NULL); + + WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + ED_undo_push(C, "Add Fake User"); + break; + } + case OUTLINER_IDOP_FAKE_CLEAR: { + /* clear fake user */ + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, id_fake_user_clear_cb, NULL); + + WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + ED_undo_push(C, "Clear Fake User"); + break; + } + case OUTLINER_IDOP_RENAME: { + /* rename */ + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL); + + WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + ED_undo_push(C, "Rename"); + break; + } + case OUTLINER_IDOP_SELECT_LINKED: + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, id_select_linked_cb, NULL); + ED_undo_push(C, "Select"); + break; + + default: + // invalid - unhandled + break; + } + + /* wrong notifier still... */ + WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + + // XXX: this is just so that outliner is always up to date + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + return OPERATOR_FINISHED; } - void OUTLINER_OT_id_operation(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Outliner ID data Operation"; - ot->idname = "OUTLINER_OT_id_operation"; + /* identifiers */ + ot->name = "Outliner ID data Operation"; + ot->idname = "OUTLINER_OT_id_operation"; - /* callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = outliner_id_operation_exec; - ot->poll = ED_operator_outliner_active; + /* callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = outliner_id_operation_exec; + ot->poll = ED_operator_outliner_active; - ot->flag = 0; + ot->flag = 0; - ot->prop = RNA_def_enum(ot->srna, "type", prop_id_op_types, 0, "ID data Operation", ""); - RNA_def_enum_funcs(ot->prop, outliner_id_operation_itemf); + ot->prop = RNA_def_enum(ot->srna, "type", prop_id_op_types, 0, "ID data Operation", ""); + RNA_def_enum_funcs(ot->prop, outliner_id_operation_itemf); } /* **************************************** */ typedef enum eOutlinerLibOpTypes { - OL_LIB_INVALID = 0, + OL_LIB_INVALID = 0, - OL_LIB_RENAME, - OL_LIB_DELETE, - OL_LIB_RELOCATE, - OL_LIB_RELOAD, + OL_LIB_RENAME, + OL_LIB_DELETE, + OL_LIB_RELOCATE, + OL_LIB_RELOAD, } eOutlinerLibOpTypes; static const EnumPropertyItem outliner_lib_op_type_items[] = { - {OL_LIB_RENAME, "RENAME", 0, "Rename", ""}, - {OL_LIB_DELETE, "DELETE", ICON_X, "Delete", "Delete this library and all its item from Blender - WARNING: no undo"}, - {OL_LIB_RELOCATE, "RELOCATE", 0, "Relocate", "Select a new path for this library, and reload all its data"}, - {OL_LIB_RELOAD, "RELOAD", ICON_FILE_REFRESH, "Reload", "Reload all data from this library"}, - {0, NULL, 0, NULL, NULL}, + {OL_LIB_RENAME, "RENAME", 0, "Rename", ""}, + {OL_LIB_DELETE, + "DELETE", + ICON_X, + "Delete", + "Delete this library and all its item from Blender - WARNING: no undo"}, + {OL_LIB_RELOCATE, + "RELOCATE", + 0, + "Relocate", + "Select a new path for this library, and reload all its data"}, + {OL_LIB_RELOAD, "RELOAD", ICON_FILE_REFRESH, "Reload", "Reload all data from this library"}, + {0, NULL, 0, NULL, NULL}, }; static int outliner_lib_operation_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - eOutlinerLibOpTypes event; - - /* check for invalid states */ - if (soops == NULL) { - return OPERATOR_CANCELLED; - } - - set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); - - event = RNA_enum_get(op->ptr, "type"); - - switch (event) { - case OL_LIB_RENAME: - { - /* rename */ - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL); - - WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); - ED_undo_push(C, "Rename Library"); - break; - } - case OL_LIB_DELETE: - { - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL); - ED_undo_push(C, "Delete Library"); - break; - } - case OL_LIB_RELOCATE: - { - /* rename */ - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, lib_relocate_cb, NULL); - ED_undo_push(C, "Relocate Library"); - break; - } - case OL_LIB_RELOAD: - { - /* rename */ - outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, lib_reload_cb, NULL); - break; - } - default: - /* invalid - unhandled */ - break; - } - - /* wrong notifier still... */ - WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); - - /* XXX: this is just so that outliner is always up to date */ - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); - - return OPERATOR_FINISHED; + Scene *scene = CTX_data_scene(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; + eOutlinerLibOpTypes event; + + /* check for invalid states */ + if (soops == NULL) { + return OPERATOR_CANCELLED; + } + + set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + + event = RNA_enum_get(op->ptr, "type"); + + switch (event) { + case OL_LIB_RENAME: { + /* rename */ + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL); + + WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + ED_undo_push(C, "Rename Library"); + break; + } + case OL_LIB_DELETE: { + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL); + ED_undo_push(C, "Delete Library"); + break; + } + case OL_LIB_RELOCATE: { + /* rename */ + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, lib_relocate_cb, NULL); + ED_undo_push(C, "Relocate Library"); + break; + } + case OL_LIB_RELOAD: { + /* rename */ + outliner_do_libdata_operation( + C, op->reports, scene, soops, &soops->tree, lib_reload_cb, NULL); + break; + } + default: + /* invalid - unhandled */ + break; + } + + /* wrong notifier still... */ + WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + + /* XXX: this is just so that outliner is always up to date */ + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); + + return OPERATOR_FINISHED; } - void OUTLINER_OT_lib_operation(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Outliner Library Operation"; - ot->idname = "OUTLINER_OT_lib_operation"; + /* identifiers */ + ot->name = "Outliner Library Operation"; + ot->idname = "OUTLINER_OT_lib_operation"; - /* callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = outliner_lib_operation_exec; - ot->poll = ED_operator_outliner_active; + /* callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = outliner_lib_operation_exec; + ot->poll = ED_operator_outliner_active; - ot->prop = RNA_def_enum(ot->srna, "type", outliner_lib_op_type_items, 0, "Library Operation", ""); + ot->prop = RNA_def_enum( + ot->srna, "type", outliner_lib_op_type_items, 0, "Library Operation", ""); } /* **************************************** */ -static void outliner_do_id_set_operation(SpaceOutliner *soops, int type, ListBase *lb, ID *newid, - void (*operation_cb)(TreeElement *, TreeStoreElem *, TreeStoreElem *, ID *)) -{ - TreeElement *te; - TreeStoreElem *tselem; - - for (te = lb->first; te; te = te->next) { - tselem = TREESTORE(te); - if (tselem->flag & TSE_SELECTED) { - if (tselem->type == type) { - TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL; - operation_cb(te, tselem, tsep, newid); - } - } - if (TSELEM_OPEN(tselem, soops)) { - outliner_do_id_set_operation(soops, type, &te->subtree, newid, operation_cb); - } - } +static void outliner_do_id_set_operation( + SpaceOutliner *soops, + int type, + ListBase *lb, + ID *newid, + void (*operation_cb)(TreeElement *, TreeStoreElem *, TreeStoreElem *, ID *)) +{ + TreeElement *te; + TreeStoreElem *tselem; + + for (te = lb->first; te; te = te->next) { + tselem = TREESTORE(te); + if (tselem->flag & TSE_SELECTED) { + if (tselem->type == type) { + TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL; + operation_cb(te, tselem, tsep, newid); + } + } + if (TSELEM_OPEN(tselem, soops)) { + outliner_do_id_set_operation(soops, type, &te->subtree, newid, operation_cb); + } + } } /* ------------------------------------------ */ -static void actionset_id_cb(TreeElement *UNUSED(te), TreeStoreElem *tselem, TreeStoreElem *tsep, ID *actId) +static void actionset_id_cb(TreeElement *UNUSED(te), + TreeStoreElem *tselem, + TreeStoreElem *tsep, + ID *actId) { - bAction *act = (bAction *)actId; + bAction *act = (bAction *)actId; - if (tselem->type == TSE_ANIM_DATA) { - /* "animation" entries - action is child of this */ - BKE_animdata_set_action(NULL, tselem->id, act); - } - /* TODO: if any other "expander" channels which own actions need to support this menu, - * add: tselem->type = ... - */ - else if (tsep && (tsep->type == TSE_ANIM_DATA)) { - /* "animation" entries case again */ - BKE_animdata_set_action(NULL, tsep->id, act); - } - // TODO: other cases not supported yet + if (tselem->type == TSE_ANIM_DATA) { + /* "animation" entries - action is child of this */ + BKE_animdata_set_action(NULL, tselem->id, act); + } + /* TODO: if any other "expander" channels which own actions need to support this menu, + * add: tselem->type = ... + */ + else if (tsep && (tsep->type == TSE_ANIM_DATA)) { + /* "animation" entries case again */ + BKE_animdata_set_action(NULL, tsep->id, act); + } + // TODO: other cases not supported yet } static int outliner_action_set_exec(bContext *C, wmOperator *op) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - - bAction *act; - - /* check for invalid states */ - if (soops == NULL) { - return OPERATOR_CANCELLED; - } - set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); - - /* get action to use */ - act = BLI_findlink(&CTX_data_main(C)->actions, RNA_enum_get(op->ptr, "action")); - - if (act == NULL) { - BKE_report(op->reports, RPT_ERROR, "No valid action to add"); - return OPERATOR_CANCELLED; - } - else if (act->idroot == 0) { - /* hopefully in this case (i.e. library of userless actions), the user knows what they're doing... */ - BKE_reportf(op->reports, RPT_WARNING, - "Action '%s' does not specify what data-blocks it can be used on " - "(try setting the 'ID Root Type' setting from the data-blocks editor " - "for this action to avoid future problems)", - act->id.name + 2); - } - - /* perform action if valid channel */ - if (datalevel == TSE_ANIM_DATA) { - outliner_do_id_set_operation(soops, datalevel, &soops->tree, (ID *)act, actionset_id_cb); - } - else if (idlevel == ID_AC) { - outliner_do_id_set_operation(soops, idlevel, &soops->tree, (ID *)act, actionset_id_cb); - } - else { - return OPERATOR_CANCELLED; - } - - /* set notifier that things have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); - ED_undo_push(C, "Set action"); - - /* done */ - return OPERATOR_FINISHED; + SpaceOutliner *soops = CTX_wm_space_outliner(C); + int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; + + bAction *act; + + /* check for invalid states */ + if (soops == NULL) { + return OPERATOR_CANCELLED; + } + set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + + /* get action to use */ + act = BLI_findlink(&CTX_data_main(C)->actions, RNA_enum_get(op->ptr, "action")); + + if (act == NULL) { + BKE_report(op->reports, RPT_ERROR, "No valid action to add"); + return OPERATOR_CANCELLED; + } + else if (act->idroot == 0) { + /* hopefully in this case (i.e. library of userless actions), the user knows what they're doing... */ + BKE_reportf(op->reports, + RPT_WARNING, + "Action '%s' does not specify what data-blocks it can be used on " + "(try setting the 'ID Root Type' setting from the data-blocks editor " + "for this action to avoid future problems)", + act->id.name + 2); + } + + /* perform action if valid channel */ + if (datalevel == TSE_ANIM_DATA) { + outliner_do_id_set_operation(soops, datalevel, &soops->tree, (ID *)act, actionset_id_cb); + } + else if (idlevel == ID_AC) { + outliner_do_id_set_operation(soops, idlevel, &soops->tree, (ID *)act, actionset_id_cb); + } + else { + return OPERATOR_CANCELLED; + } + + /* set notifier that things have changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); + ED_undo_push(C, "Set action"); + + /* done */ + return OPERATOR_FINISHED; } void OUTLINER_OT_action_set(wmOperatorType *ot) { - PropertyRNA *prop; + PropertyRNA *prop; - /* identifiers */ - ot->name = "Outliner Set Action"; - ot->idname = "OUTLINER_OT_action_set"; - ot->description = "Change the active action used"; + /* identifiers */ + ot->name = "Outliner Set Action"; + ot->idname = "OUTLINER_OT_action_set"; + ot->description = "Change the active action used"; - /* api callbacks */ - ot->invoke = WM_enum_search_invoke; - ot->exec = outliner_action_set_exec; - ot->poll = ED_operator_outliner_active; + /* api callbacks */ + ot->invoke = WM_enum_search_invoke; + ot->exec = outliner_action_set_exec; + ot->poll = ED_operator_outliner_active; - /* flags */ - ot->flag = 0; + /* flags */ + ot->flag = 0; - /* props */ - // TODO: this would be nicer as an ID-pointer... - prop = RNA_def_enum(ot->srna, "action", DummyRNA_NULL_items, 0, "Action", ""); - RNA_def_enum_funcs(prop, RNA_action_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); - ot->prop = prop; + /* props */ + // TODO: this would be nicer as an ID-pointer... + prop = RNA_def_enum(ot->srna, "action", DummyRNA_NULL_items, 0, "Action", ""); + RNA_def_enum_funcs(prop, RNA_action_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; } /* **************************************** */ typedef enum eOutliner_AnimDataOps { - OUTLINER_ANIMOP_INVALID = 0, + OUTLINER_ANIMOP_INVALID = 0, - OUTLINER_ANIMOP_CLEAR_ADT, + OUTLINER_ANIMOP_CLEAR_ADT, - OUTLINER_ANIMOP_SET_ACT, - OUTLINER_ANIMOP_CLEAR_ACT, + OUTLINER_ANIMOP_SET_ACT, + OUTLINER_ANIMOP_CLEAR_ACT, - OUTLINER_ANIMOP_REFRESH_DRV, - OUTLINER_ANIMOP_CLEAR_DRV + OUTLINER_ANIMOP_REFRESH_DRV, + OUTLINER_ANIMOP_CLEAR_DRV - //OUTLINER_ANIMOP_COPY_DRIVERS, - //OUTLINER_ANIMOP_PASTE_DRIVERS + //OUTLINER_ANIMOP_COPY_DRIVERS, + //OUTLINER_ANIMOP_PASTE_DRIVERS } eOutliner_AnimDataOps; static const EnumPropertyItem prop_animdata_op_types[] = { - {OUTLINER_ANIMOP_CLEAR_ADT, "CLEAR_ANIMDATA", 0, "Clear Animation Data", "Remove this animation data container"}, - {OUTLINER_ANIMOP_SET_ACT, "SET_ACT", 0, "Set Action", ""}, - {OUTLINER_ANIMOP_CLEAR_ACT, "CLEAR_ACT", 0, "Unlink Action", ""}, - {OUTLINER_ANIMOP_REFRESH_DRV, "REFRESH_DRIVERS", 0, "Refresh Drivers", ""}, - //{OUTLINER_ANIMOP_COPY_DRIVERS, "COPY_DRIVERS", 0, "Copy Drivers", ""}, - //{OUTLINER_ANIMOP_PASTE_DRIVERS, "PASTE_DRIVERS", 0, "Paste Drivers", ""}, - {OUTLINER_ANIMOP_CLEAR_DRV, "CLEAR_DRIVERS", 0, "Clear Drivers", ""}, - {0, NULL, 0, NULL, NULL}, + {OUTLINER_ANIMOP_CLEAR_ADT, + "CLEAR_ANIMDATA", + 0, + "Clear Animation Data", + "Remove this animation data container"}, + {OUTLINER_ANIMOP_SET_ACT, "SET_ACT", 0, "Set Action", ""}, + {OUTLINER_ANIMOP_CLEAR_ACT, "CLEAR_ACT", 0, "Unlink Action", ""}, + {OUTLINER_ANIMOP_REFRESH_DRV, "REFRESH_DRIVERS", 0, "Refresh Drivers", ""}, + //{OUTLINER_ANIMOP_COPY_DRIVERS, "COPY_DRIVERS", 0, "Copy Drivers", ""}, + //{OUTLINER_ANIMOP_PASTE_DRIVERS, "PASTE_DRIVERS", 0, "Paste Drivers", ""}, + {OUTLINER_ANIMOP_CLEAR_DRV, "CLEAR_DRIVERS", 0, "Clear Drivers", ""}, + {0, NULL, 0, NULL, NULL}, }; static int outliner_animdata_operation_exec(bContext *C, wmOperator *op) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - eOutliner_AnimDataOps event; - short updateDeps = 0; + SpaceOutliner *soops = CTX_wm_space_outliner(C); + int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; + eOutliner_AnimDataOps event; + short updateDeps = 0; - /* check for invalid states */ - if (soops == NULL) { - return OPERATOR_CANCELLED; - } + /* check for invalid states */ + if (soops == NULL) { + return OPERATOR_CANCELLED; + } - event = RNA_enum_get(op->ptr, "type"); - set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + event = RNA_enum_get(op->ptr, "type"); + set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); - if (datalevel != TSE_ANIM_DATA) { - return OPERATOR_CANCELLED; - } + if (datalevel != TSE_ANIM_DATA) { + return OPERATOR_CANCELLED; + } - /* perform the core operation */ - switch (event) { - case OUTLINER_ANIMOP_CLEAR_ADT: - /* Remove Animation Data - this may remove the active action, in some cases... */ - outliner_do_data_operation(soops, datalevel, event, &soops->tree, clear_animdata_cb, NULL); + /* perform the core operation */ + switch (event) { + case OUTLINER_ANIMOP_CLEAR_ADT: + /* Remove Animation Data - this may remove the active action, in some cases... */ + outliner_do_data_operation(soops, datalevel, event, &soops->tree, clear_animdata_cb, NULL); - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); - ED_undo_push(C, "Clear Animation Data"); - break; + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); + ED_undo_push(C, "Clear Animation Data"); + break; - case OUTLINER_ANIMOP_SET_ACT: - /* delegate once again... */ - WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, NULL); - break; + case OUTLINER_ANIMOP_SET_ACT: + /* delegate once again... */ + WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, NULL); + break; - case OUTLINER_ANIMOP_CLEAR_ACT: - /* clear active action - using standard rules */ - outliner_do_data_operation(soops, datalevel, event, &soops->tree, unlinkact_animdata_cb, NULL); + case OUTLINER_ANIMOP_CLEAR_ACT: + /* clear active action - using standard rules */ + outliner_do_data_operation( + soops, datalevel, event, &soops->tree, unlinkact_animdata_cb, NULL); - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); - ED_undo_push(C, "Unlink action"); - break; + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); + ED_undo_push(C, "Unlink action"); + break; - case OUTLINER_ANIMOP_REFRESH_DRV: - outliner_do_data_operation(soops, datalevel, event, &soops->tree, refreshdrivers_animdata_cb, NULL); + case OUTLINER_ANIMOP_REFRESH_DRV: + outliner_do_data_operation( + soops, datalevel, event, &soops->tree, refreshdrivers_animdata_cb, NULL); - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, NULL); - //ED_undo_push(C, "Refresh Drivers"); /* no undo needed - shouldn't have any impact? */ - updateDeps = 1; - break; + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, NULL); + //ED_undo_push(C, "Refresh Drivers"); /* no undo needed - shouldn't have any impact? */ + updateDeps = 1; + break; - case OUTLINER_ANIMOP_CLEAR_DRV: - outliner_do_data_operation(soops, datalevel, event, &soops->tree, cleardrivers_animdata_cb, NULL); + case OUTLINER_ANIMOP_CLEAR_DRV: + outliner_do_data_operation( + soops, datalevel, event, &soops->tree, cleardrivers_animdata_cb, NULL); - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, NULL); - ED_undo_push(C, "Clear Drivers"); - updateDeps = 1; - break; + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, NULL); + ED_undo_push(C, "Clear Drivers"); + updateDeps = 1; + break; - default: // invalid - break; - } + default: // invalid + break; + } - /* update dependencies */ - if (updateDeps) { - /* rebuild depsgraph for the new deps */ - DEG_relations_tag_update(CTX_data_main(C)); - } + /* update dependencies */ + if (updateDeps) { + /* rebuild depsgraph for the new deps */ + DEG_relations_tag_update(CTX_data_main(C)); + } - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } - void OUTLINER_OT_animdata_operation(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Outliner Animation Data Operation"; - ot->idname = "OUTLINER_OT_animdata_operation"; + /* identifiers */ + ot->name = "Outliner Animation Data Operation"; + ot->idname = "OUTLINER_OT_animdata_operation"; - /* callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = outliner_animdata_operation_exec; - ot->poll = ED_operator_outliner_active; + /* callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = outliner_animdata_operation_exec; + ot->poll = ED_operator_outliner_active; - ot->flag = 0; + ot->flag = 0; - ot->prop = RNA_def_enum(ot->srna, "type", prop_animdata_op_types, 0, "Animation Operation", ""); + ot->prop = RNA_def_enum(ot->srna, "type", prop_animdata_op_types, 0, "Animation Operation", ""); } /* **************************************** */ static const EnumPropertyItem prop_constraint_op_types[] = { - {OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_HIDE_OFF, "Enable", ""}, - {OL_CONSTRAINTOP_DISABLE, "DISABLE", ICON_HIDE_ON, "Disable", ""}, - {OL_CONSTRAINTOP_DELETE, "DELETE", ICON_X, "Delete", ""}, - {0, NULL, 0, NULL, NULL}, + {OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_HIDE_OFF, "Enable", ""}, + {OL_CONSTRAINTOP_DISABLE, "DISABLE", ICON_HIDE_ON, "Disable", ""}, + {OL_CONSTRAINTOP_DELETE, "DELETE", ICON_X, "Delete", ""}, + {0, NULL, 0, NULL, NULL}, }; static int outliner_constraint_operation_exec(bContext *C, wmOperator *op) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - eOutliner_PropConstraintOps event; + SpaceOutliner *soops = CTX_wm_space_outliner(C); + int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; + eOutliner_PropConstraintOps event; - event = RNA_enum_get(op->ptr, "type"); - set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + event = RNA_enum_get(op->ptr, "type"); + set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); - outliner_do_data_operation(soops, datalevel, event, &soops->tree, constraint_cb, C); + outliner_do_data_operation(soops, datalevel, event, &soops->tree, constraint_cb, C); - if (event == OL_CONSTRAINTOP_DELETE) { - outliner_cleanup_tree(soops); - } + if (event == OL_CONSTRAINTOP_DELETE) { + outliner_cleanup_tree(soops); + } - ED_undo_push(C, "Constraint operation"); + ED_undo_push(C, "Constraint operation"); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_constraint_operation(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Outliner Constraint Operation"; - ot->idname = "OUTLINER_OT_constraint_operation"; + /* identifiers */ + ot->name = "Outliner Constraint Operation"; + ot->idname = "OUTLINER_OT_constraint_operation"; - /* callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = outliner_constraint_operation_exec; - ot->poll = ED_operator_outliner_active; + /* callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = outliner_constraint_operation_exec; + ot->poll = ED_operator_outliner_active; - ot->flag = 0; + ot->flag = 0; - ot->prop = RNA_def_enum(ot->srna, "type", prop_constraint_op_types, 0, "Constraint Operation", ""); + ot->prop = RNA_def_enum( + ot->srna, "type", prop_constraint_op_types, 0, "Constraint Operation", ""); } /* ******************** */ static const EnumPropertyItem prop_modifier_op_types[] = { - {OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle viewport use", ""}, - {OL_MODIFIER_OP_TOGREN, "TOGREN", ICON_RESTRICT_RENDER_OFF, "Toggle render use", ""}, - {OL_MODIFIER_OP_DELETE, "DELETE", ICON_X, "Delete", ""}, - {0, NULL, 0, NULL, NULL}, + {OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle viewport use", ""}, + {OL_MODIFIER_OP_TOGREN, "TOGREN", ICON_RESTRICT_RENDER_OFF, "Toggle render use", ""}, + {OL_MODIFIER_OP_DELETE, "DELETE", ICON_X, "Delete", ""}, + {0, NULL, 0, NULL, NULL}, }; static int outliner_modifier_operation_exec(bContext *C, wmOperator *op) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - eOutliner_PropModifierOps event; + SpaceOutliner *soops = CTX_wm_space_outliner(C); + int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; + eOutliner_PropModifierOps event; - event = RNA_enum_get(op->ptr, "type"); - set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + event = RNA_enum_get(op->ptr, "type"); + set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); - outliner_do_data_operation(soops, datalevel, event, &soops->tree, modifier_cb, C); + outliner_do_data_operation(soops, datalevel, event, &soops->tree, modifier_cb, C); - if (event == OL_MODIFIER_OP_DELETE) { - outliner_cleanup_tree(soops); - } + if (event == OL_MODIFIER_OP_DELETE) { + outliner_cleanup_tree(soops); + } - ED_undo_push(C, "Modifier operation"); + ED_undo_push(C, "Modifier operation"); - return OPERATOR_FINISHED; + return OPERATOR_FINISHED; } void OUTLINER_OT_modifier_operation(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Outliner Modifier Operation"; - ot->idname = "OUTLINER_OT_modifier_operation"; + /* identifiers */ + ot->name = "Outliner Modifier Operation"; + ot->idname = "OUTLINER_OT_modifier_operation"; - /* callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = outliner_modifier_operation_exec; - ot->poll = ED_operator_outliner_active; + /* callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = outliner_modifier_operation_exec; + ot->poll = ED_operator_outliner_active; - ot->flag = 0; + ot->flag = 0; - ot->prop = RNA_def_enum(ot->srna, "type", prop_modifier_op_types, 0, "Modifier Operation", ""); + ot->prop = RNA_def_enum(ot->srna, "type", prop_modifier_op_types, 0, "Modifier Operation", ""); } /* ******************** */ // XXX: select linked is for RNA structs only static const EnumPropertyItem prop_data_op_types[] = { - {OL_DOP_SELECT, "SELECT", 0, "Select", ""}, - {OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""}, - {OL_DOP_HIDE, "HIDE", 0, "Hide", ""}, - {OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""}, - {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""}, - {0, NULL, 0, NULL, NULL}, + {OL_DOP_SELECT, "SELECT", 0, "Select", ""}, + {OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""}, + {OL_DOP_HIDE, "HIDE", 0, "Hide", ""}, + {OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""}, + {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""}, + {0, NULL, 0, NULL, NULL}, }; static int outliner_data_operation_exec(bContext *C, wmOperator *op) { - SpaceOutliner *soops = CTX_wm_space_outliner(C); - int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - eOutliner_PropDataOps event; - - /* check for invalid states */ - if (soops == NULL) { - return OPERATOR_CANCELLED; - } - - event = RNA_enum_get(op->ptr, "type"); - set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); - - switch (datalevel) { - case TSE_POSE_CHANNEL: - { - outliner_do_data_operation(soops, datalevel, event, &soops->tree, pchan_cb, NULL); - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); - ED_undo_push(C, "PoseChannel operation"); - - break; - } - case TSE_BONE: - { - outliner_do_data_operation(soops, datalevel, event, &soops->tree, bone_cb, NULL); - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); - ED_undo_push(C, "Bone operation"); - - break; - } - case TSE_EBONE: - { - outliner_do_data_operation(soops, datalevel, event, &soops->tree, ebone_cb, NULL); - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); - ED_undo_push(C, "EditBone operation"); - - break; - } - case TSE_SEQUENCE: - { - Scene *scene = CTX_data_scene(C); - outliner_do_data_operation(soops, datalevel, event, &soops->tree, sequence_cb, scene); - - break; - } - case TSE_GP_LAYER: - { - outliner_do_data_operation(soops, datalevel, event, &soops->tree, gp_layer_cb, NULL); - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); - ED_undo_push(C, "Grease Pencil Layer operation"); - - break; - } - case TSE_RNA_STRUCT: - if (event == OL_DOP_SELECT_LINKED) { - outliner_do_data_operation(soops, datalevel, event, &soops->tree, data_select_linked_cb, C); - } - - break; - - default: - BKE_report(op->reports, RPT_WARNING, "Not yet implemented"); - break; - } - - return OPERATOR_FINISHED; + SpaceOutliner *soops = CTX_wm_space_outliner(C); + int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; + eOutliner_PropDataOps event; + + /* check for invalid states */ + if (soops == NULL) { + return OPERATOR_CANCELLED; + } + + event = RNA_enum_get(op->ptr, "type"); + set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + + switch (datalevel) { + case TSE_POSE_CHANNEL: { + outliner_do_data_operation(soops, datalevel, event, &soops->tree, pchan_cb, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + ED_undo_push(C, "PoseChannel operation"); + + break; + } + case TSE_BONE: { + outliner_do_data_operation(soops, datalevel, event, &soops->tree, bone_cb, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + ED_undo_push(C, "Bone operation"); + + break; + } + case TSE_EBONE: { + outliner_do_data_operation(soops, datalevel, event, &soops->tree, ebone_cb, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + ED_undo_push(C, "EditBone operation"); + + break; + } + case TSE_SEQUENCE: { + Scene *scene = CTX_data_scene(C); + outliner_do_data_operation(soops, datalevel, event, &soops->tree, sequence_cb, scene); + + break; + } + case TSE_GP_LAYER: { + outliner_do_data_operation(soops, datalevel, event, &soops->tree, gp_layer_cb, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); + ED_undo_push(C, "Grease Pencil Layer operation"); + + break; + } + case TSE_RNA_STRUCT: + if (event == OL_DOP_SELECT_LINKED) { + outliner_do_data_operation( + soops, datalevel, event, &soops->tree, data_select_linked_cb, C); + } + + break; + + default: + BKE_report(op->reports, RPT_WARNING, "Not yet implemented"); + break; + } + + return OPERATOR_FINISHED; } - void OUTLINER_OT_data_operation(wmOperatorType *ot) { - /* identifiers */ - ot->name = "Outliner Data Operation"; - ot->idname = "OUTLINER_OT_data_operation"; + /* identifiers */ + ot->name = "Outliner Data Operation"; + ot->idname = "OUTLINER_OT_data_operation"; - /* callbacks */ - ot->invoke = WM_menu_invoke; - ot->exec = outliner_data_operation_exec; - ot->poll = ED_operator_outliner_active; + /* callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = outliner_data_operation_exec; + ot->poll = ED_operator_outliner_active; - ot->flag = 0; + ot->flag = 0; - ot->prop = RNA_def_enum(ot->srna, "type", prop_data_op_types, 0, "Data Operation", ""); + ot->prop = RNA_def_enum(ot->srna, "type", prop_data_op_types, 0, "Data Operation", ""); } - /* ******************** */ static int outliner_operator_menu(bContext *C, const char *opname) { - wmOperatorType *ot = WM_operatortype_find(opname, false); - uiPopupMenu *pup = UI_popup_menu_begin(C, RNA_struct_ui_name(ot->srna), ICON_NONE); - uiLayout *layout = UI_popup_menu_layout(pup); - - /* set this so the default execution context is the same as submenus */ - uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN); - uiItemsEnumO(layout, ot->idname, RNA_property_identifier(ot->prop)); - - MenuType *mt = WM_menutype_find("OUTLINER_MT_context", false); - if (mt) { - uiItemS(layout); - UI_menutype_draw(C, mt, layout); - } - - UI_popup_menu_end(C, pup); - - return OPERATOR_INTERFACE; -} - -static int do_outliner_operation_event(bContext *C, ARegion *ar, SpaceOutliner *soops, - TreeElement *te, const float mval[2]) -{ - ReportList *reports = CTX_wm_reports(C); // XXX... - - if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { - int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; - TreeStoreElem *tselem = TREESTORE(te); - - /* select object that's clicked on and popup context menu */ - if (!(tselem->flag & TSE_SELECTED)) { - - if (outliner_flag_is_any_test(&soops->tree, TSE_SELECTED, 1)) { - outliner_flag_set(&soops->tree, TSE_SELECTED, 0); - } - - tselem->flag |= TSE_SELECTED; - - /* Only redraw, don't rebuild here because TreeElement pointers will - * become invalid and operations will crash. */ - ED_region_tag_redraw_no_rebuild(ar); - } - - set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); - - if (scenelevel) { - if (objectlevel || datalevel || idlevel) { - BKE_report(reports, RPT_WARNING, "Mixed selection"); - return OPERATOR_CANCELLED; - } - else { - return outliner_operator_menu(C, "OUTLINER_OT_scene_operation"); - } - } - else if (objectlevel) { - WM_menu_name_call(C, "OUTLINER_MT_object", WM_OP_INVOKE_REGION_WIN); - return OPERATOR_FINISHED; - } - else if (idlevel) { - if (idlevel == -1 || datalevel) { - BKE_report(reports, RPT_WARNING, "Mixed selection"); - return OPERATOR_CANCELLED; - } - else { - switch (idlevel) { - case ID_GR: - WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN); - return OPERATOR_FINISHED; - break; - case ID_LI: - return outliner_operator_menu(C, "OUTLINER_OT_lib_operation"); - break; - default: - return outliner_operator_menu(C, "OUTLINER_OT_id_operation"); - break; - } - } - } - else if (datalevel) { - if (datalevel == -1) { - BKE_report(reports, RPT_WARNING, "Mixed selection"); - return OPERATOR_CANCELLED; - } - else { - if (datalevel == TSE_ANIM_DATA) { - return outliner_operator_menu(C, "OUTLINER_OT_animdata_operation"); - } - else if (datalevel == TSE_DRIVER_BASE) { - /* do nothing... no special ops needed yet */ - return OPERATOR_CANCELLED; - } - else if (datalevel == TSE_LAYER_COLLECTION) { - WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN); - return OPERATOR_FINISHED; - } - else if (ELEM(datalevel, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { - WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN); - return OPERATOR_FINISHED; - } - else if (datalevel == TSE_ID_BASE) { - /* do nothing... there are no ops needed here yet */ - } - else if (datalevel == TSE_CONSTRAINT) { - return outliner_operator_menu(C, "OUTLINER_OT_constraint_operation"); - } - else if (datalevel == TSE_MODIFIER) { - return outliner_operator_menu(C, "OUTLINER_OT_modifier_operation"); - } - else { - return outliner_operator_menu(C, "OUTLINER_OT_data_operation"); - } - } - } - - return 0; - } - - for (te = te->subtree.first; te; te = te->next) { - int retval = do_outliner_operation_event(C, ar, soops, te, mval); - if (retval) { - return retval; - } - } - - return 0; + wmOperatorType *ot = WM_operatortype_find(opname, false); + uiPopupMenu *pup = UI_popup_menu_begin(C, RNA_struct_ui_name(ot->srna), ICON_NONE); + uiLayout *layout = UI_popup_menu_layout(pup); + + /* set this so the default execution context is the same as submenus */ + uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN); + uiItemsEnumO(layout, ot->idname, RNA_property_identifier(ot->prop)); + + MenuType *mt = WM_menutype_find("OUTLINER_MT_context", false); + if (mt) { + uiItemS(layout); + UI_menutype_draw(C, mt, layout); + } + + UI_popup_menu_end(C, pup); + + return OPERATOR_INTERFACE; +} + +static int do_outliner_operation_event( + bContext *C, ARegion *ar, SpaceOutliner *soops, TreeElement *te, const float mval[2]) +{ + ReportList *reports = CTX_wm_reports(C); // XXX... + + if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { + int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; + TreeStoreElem *tselem = TREESTORE(te); + + /* select object that's clicked on and popup context menu */ + if (!(tselem->flag & TSE_SELECTED)) { + + if (outliner_flag_is_any_test(&soops->tree, TSE_SELECTED, 1)) { + outliner_flag_set(&soops->tree, TSE_SELECTED, 0); + } + + tselem->flag |= TSE_SELECTED; + + /* Only redraw, don't rebuild here because TreeElement pointers will + * become invalid and operations will crash. */ + ED_region_tag_redraw_no_rebuild(ar); + } + + set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel); + + if (scenelevel) { + if (objectlevel || datalevel || idlevel) { + BKE_report(reports, RPT_WARNING, "Mixed selection"); + return OPERATOR_CANCELLED; + } + else { + return outliner_operator_menu(C, "OUTLINER_OT_scene_operation"); + } + } + else if (objectlevel) { + WM_menu_name_call(C, "OUTLINER_MT_object", WM_OP_INVOKE_REGION_WIN); + return OPERATOR_FINISHED; + } + else if (idlevel) { + if (idlevel == -1 || datalevel) { + BKE_report(reports, RPT_WARNING, "Mixed selection"); + return OPERATOR_CANCELLED; + } + else { + switch (idlevel) { + case ID_GR: + WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN); + return OPERATOR_FINISHED; + break; + case ID_LI: + return outliner_operator_menu(C, "OUTLINER_OT_lib_operation"); + break; + default: + return outliner_operator_menu(C, "OUTLINER_OT_id_operation"); + break; + } + } + } + else if (datalevel) { + if (datalevel == -1) { + BKE_report(reports, RPT_WARNING, "Mixed selection"); + return OPERATOR_CANCELLED; + } + else { + if (datalevel == TSE_ANIM_DATA) { + return outliner_operator_menu(C, "OUTLINER_OT_animdata_operation"); + } + else if (datalevel == TSE_DRIVER_BASE) { + /* do nothing... no special ops needed yet */ + return OPERATOR_CANCELLED; + } + else if (datalevel == TSE_LAYER_COLLECTION) { + WM_menu_name_call(C, "OUTLINER_MT_collection", WM_OP_INVOKE_REGION_WIN); + return OPERATOR_FINISHED; + } + else if (ELEM(datalevel, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { + WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN); + return OPERATOR_FINISHED; + } + else if (datalevel == TSE_ID_BASE) { + /* do nothing... there are no ops needed here yet */ + } + else if (datalevel == TSE_CONSTRAINT) { + return outliner_operator_menu(C, "OUTLINER_OT_constraint_operation"); + } + else if (datalevel == TSE_MODIFIER) { + return outliner_operator_menu(C, "OUTLINER_OT_modifier_operation"); + } + else { + return outliner_operator_menu(C, "OUTLINER_OT_data_operation"); + } + } + } + + return 0; + } + + for (te = te->subtree.first; te; te = te->next) { + int retval = do_outliner_operation_event(C, ar, soops, te, mval); + if (retval) { + return retval; + } + } + + return 0; } - static int outliner_operation(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { - ARegion *ar = CTX_wm_region(C); - SpaceOutliner *soops = CTX_wm_space_outliner(C); - uiBut *but = UI_context_active_but_get(C); - TreeElement *te; - float fmval[2]; + ARegion *ar = CTX_wm_region(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + uiBut *but = UI_context_active_but_get(C); + TreeElement *te; + float fmval[2]; - if (but) { - UI_but_tooltip_timer_remove(C, but); - } + if (but) { + UI_but_tooltip_timer_remove(C, but); + } - UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); - for (te = soops->tree.first; te; te = te->next) { - int retval = do_outliner_operation_event(C, ar, soops, te, fmval); - if (retval) { - return retval; - } - } + for (te = soops->tree.first; te; te = te->next) { + int retval = do_outliner_operation_event(C, ar, soops, te, fmval); + if (retval) { + return retval; + } + } - /* Menus for clicking in empty space. */ - if (soops->outlinevis == SO_VIEW_LAYER) { - WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN); - return OPERATOR_FINISHED; - } + /* Menus for clicking in empty space. */ + if (soops->outlinevis == SO_VIEW_LAYER) { + WM_menu_name_call(C, "OUTLINER_MT_collection_new", WM_OP_INVOKE_REGION_WIN); + return OPERATOR_FINISHED; + } - WM_menu_name_call(C, "OUTLINER_MT_context", WM_OP_INVOKE_REGION_WIN); - return OPERATOR_FINISHED; + WM_menu_name_call(C, "OUTLINER_MT_context", WM_OP_INVOKE_REGION_WIN); + return OPERATOR_FINISHED; } /* Menu only! Calls other operators */ void OUTLINER_OT_operation(wmOperatorType *ot) { - ot->name = "Context Menu"; - ot->idname = "OUTLINER_OT_operation"; - ot->description = "Context menu for item operations"; + ot->name = "Context Menu"; + ot->idname = "OUTLINER_OT_operation"; + ot->description = "Context menu for item operations"; - ot->invoke = outliner_operation; + ot->invoke = outliner_operation; - ot->poll = ED_operator_outliner_active; + ot->poll = ED_operator_outliner_active; } /* ****************************************************** */ diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index a4e512d6846..a03d9b6fb6d 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -83,8 +83,9 @@ #endif /* prototypes */ -static TreeElement *outliner_add_collection_recursive( - SpaceOutliner *soops, Collection *collection, TreeElement *ten); +static TreeElement *outliner_add_collection_recursive(SpaceOutliner *soops, + Collection *collection, + TreeElement *ten); static void outliner_make_object_parent_hierarchy(ListBase *lb); /* ********************************************************* */ @@ -92,98 +93,97 @@ static void outliner_make_object_parent_hierarchy(ListBase *lb); static void outliner_storage_cleanup(SpaceOutliner *soops) { - BLI_mempool *ts = soops->treestore; - - if (ts) { - TreeStoreElem *tselem; - int unused = 0; - - /* each element used once, for ID blocks with more users to have each a treestore */ - BLI_mempool_iter iter; - - BLI_mempool_iternew(ts, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - tselem->used = 0; - } - - /* cleanup only after reading file or undo step, and always for - * RNA datablocks view in order to save memory */ - if (soops->storeflag & SO_TREESTORE_CLEANUP) { - soops->storeflag &= ~SO_TREESTORE_CLEANUP; - - BLI_mempool_iternew(ts, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - if (tselem->id == NULL) { - unused++; - } - } - - if (unused) { - if (BLI_mempool_len(ts) == unused) { - BLI_mempool_destroy(ts); - soops->treestore = NULL; - if (soops->treehash) { - BKE_outliner_treehash_free(soops->treehash); - soops->treehash = NULL; - } - } - else { - TreeStoreElem *tsenew; - BLI_mempool *new_ts = BLI_mempool_create(sizeof(TreeStoreElem), BLI_mempool_len(ts) - unused, - 512, BLI_MEMPOOL_ALLOW_ITER); - BLI_mempool_iternew(ts, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - if (tselem->id) { - tsenew = BLI_mempool_alloc(new_ts); - *tsenew = *tselem; - } - } - BLI_mempool_destroy(ts); - soops->treestore = new_ts; - if (soops->treehash) { - /* update hash table to fix broken pointers */ - BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore); - } - } - } - } - else if (soops->treehash) { - BKE_outliner_treehash_clear_used(soops->treehash); - } - } + BLI_mempool *ts = soops->treestore; + + if (ts) { + TreeStoreElem *tselem; + int unused = 0; + + /* each element used once, for ID blocks with more users to have each a treestore */ + BLI_mempool_iter iter; + + BLI_mempool_iternew(ts, &iter); + while ((tselem = BLI_mempool_iterstep(&iter))) { + tselem->used = 0; + } + + /* cleanup only after reading file or undo step, and always for + * RNA datablocks view in order to save memory */ + if (soops->storeflag & SO_TREESTORE_CLEANUP) { + soops->storeflag &= ~SO_TREESTORE_CLEANUP; + + BLI_mempool_iternew(ts, &iter); + while ((tselem = BLI_mempool_iterstep(&iter))) { + if (tselem->id == NULL) { + unused++; + } + } + + if (unused) { + if (BLI_mempool_len(ts) == unused) { + BLI_mempool_destroy(ts); + soops->treestore = NULL; + if (soops->treehash) { + BKE_outliner_treehash_free(soops->treehash); + soops->treehash = NULL; + } + } + else { + TreeStoreElem *tsenew; + BLI_mempool *new_ts = BLI_mempool_create( + sizeof(TreeStoreElem), BLI_mempool_len(ts) - unused, 512, BLI_MEMPOOL_ALLOW_ITER); + BLI_mempool_iternew(ts, &iter); + while ((tselem = BLI_mempool_iterstep(&iter))) { + if (tselem->id) { + tsenew = BLI_mempool_alloc(new_ts); + *tsenew = *tselem; + } + } + BLI_mempool_destroy(ts); + soops->treestore = new_ts; + if (soops->treehash) { + /* update hash table to fix broken pointers */ + BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore); + } + } + } + } + else if (soops->treehash) { + BKE_outliner_treehash_clear_used(soops->treehash); + } + } } static void check_persistent(SpaceOutliner *soops, TreeElement *te, ID *id, short type, short nr) { - TreeStoreElem *tselem; - - if (soops->treestore == NULL) { - /* if treestore was not created in readfile.c, create it here */ - soops->treestore = BLI_mempool_create(sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER); - - } - if (soops->treehash == NULL) { - soops->treehash = BKE_outliner_treehash_create_from_treestore(soops->treestore); - } - - /* find any unused tree element in treestore and mark it as used - * (note that there may be multiple unused elements in case of linked objects) */ - tselem = BKE_outliner_treehash_lookup_unused(soops->treehash, type, nr, id); - if (tselem) { - te->store_elem = tselem; - tselem->used = 1; - return; - } - - /* add 1 element to treestore */ - tselem = BLI_mempool_alloc(soops->treestore); - tselem->type = type; - tselem->nr = type ? nr : 0; - tselem->id = id; - tselem->used = 0; - tselem->flag = TSE_CLOSED; - te->store_elem = tselem; - BKE_outliner_treehash_add_element(soops->treehash, tselem); + TreeStoreElem *tselem; + + if (soops->treestore == NULL) { + /* if treestore was not created in readfile.c, create it here */ + soops->treestore = BLI_mempool_create(sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER); + } + if (soops->treehash == NULL) { + soops->treehash = BKE_outliner_treehash_create_from_treestore(soops->treestore); + } + + /* find any unused tree element in treestore and mark it as used + * (note that there may be multiple unused elements in case of linked objects) */ + tselem = BKE_outliner_treehash_lookup_unused(soops->treehash, type, nr, id); + if (tselem) { + te->store_elem = tselem; + tselem->used = 1; + return; + } + + /* add 1 element to treestore */ + tselem = BLI_mempool_alloc(soops->treestore); + tselem->type = type; + tselem->nr = type ? nr : 0; + tselem->id = id; + tselem->used = 0; + tselem->flag = TSE_CLOSED; + te->store_elem = tselem; + BKE_outliner_treehash_add_element(soops->treehash, tselem); } /* ********************************************************* */ @@ -191,16 +191,16 @@ static void check_persistent(SpaceOutliner *soops, TreeElement *te, ID *id, shor void outliner_free_tree(ListBase *tree) { - for (TreeElement *element = tree->first, *element_next; element; element = element_next) { - element_next = element->next; - outliner_free_tree_element(element, tree); - } + for (TreeElement *element = tree->first, *element_next; element; element = element_next) { + element_next = element->next; + outliner_free_tree_element(element, tree); + } } void outliner_cleanup_tree(SpaceOutliner *soops) { - outliner_free_tree(&soops->tree); - outliner_storage_cleanup(soops); + outliner_free_tree(&soops->tree); + outliner_storage_cleanup(soops); } /** @@ -211,926 +211,924 @@ void outliner_cleanup_tree(SpaceOutliner *soops) */ void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree) { - BLI_assert(BLI_findindex(parent_subtree, element) > -1); - BLI_remlink(parent_subtree, element); + BLI_assert(BLI_findindex(parent_subtree, element) > -1); + BLI_remlink(parent_subtree, element); - outliner_free_tree(&element->subtree); + outliner_free_tree(&element->subtree); - if (element->flag & TE_FREE_NAME) { - MEM_freeN((void *)element->name); - } - MEM_freeN(element); + if (element->flag & TE_FREE_NAME) { + MEM_freeN((void *)element->name); + } + MEM_freeN(element); } - /* ********************************************************* */ /* Prototype, see functions below */ -static TreeElement *outliner_add_element(SpaceOutliner *soops, ListBase *lb, void *idv, - TreeElement *parent, short type, short index); +static TreeElement *outliner_add_element( + SpaceOutliner *soops, ListBase *lb, void *idv, TreeElement *parent, short type, short index); /* -------------------------------------------------------- */ /* special handling of hierarchical non-lib data */ -static void outliner_add_bone(SpaceOutliner *soops, ListBase *lb, ID *id, Bone *curBone, - TreeElement *parent, int *a) +static void outliner_add_bone( + SpaceOutliner *soops, ListBase *lb, ID *id, Bone *curBone, TreeElement *parent, int *a) { - TreeElement *te = outliner_add_element(soops, lb, id, parent, TSE_BONE, *a); + TreeElement *te = outliner_add_element(soops, lb, id, parent, TSE_BONE, *a); - (*a)++; - te->name = curBone->name; - te->directdata = curBone; + (*a)++; + te->name = curBone->name; + te->directdata = curBone; - for (curBone = curBone->childbase.first; curBone; curBone = curBone->next) { - outliner_add_bone(soops, &te->subtree, id, curBone, te, a); - } + for (curBone = curBone->childbase.first; curBone; curBone = curBone->next) { + outliner_add_bone(soops, &te->subtree, id, curBone, te, a); + } } static bool outliner_animdata_test(AnimData *adt) { - if (adt) { - return (adt->action || adt->drivers.first || adt->nla_tracks.first); - } - return false; + if (adt) { + return (adt->action || adt->drivers.first || adt->nla_tracks.first); + } + return false; } #ifdef WITH_FREESTYLE -static void outliner_add_line_styles(SpaceOutliner *soops, ListBase *lb, Scene *sce, TreeElement *te) +static void outliner_add_line_styles(SpaceOutliner *soops, + ListBase *lb, + Scene *sce, + TreeElement *te) { - ViewLayer *view_layer; - FreestyleLineSet *lineset; - - for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { - for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) { - FreestyleLineStyle *linestyle = lineset->linestyle; - if (linestyle) { - linestyle->id.tag |= LIB_TAG_DOIT; - } - } - } - for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { - for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) { - FreestyleLineStyle *linestyle = lineset->linestyle; - if (linestyle) { - if (!(linestyle->id.tag & LIB_TAG_DOIT)) { - continue; - } - linestyle->id.tag &= ~LIB_TAG_DOIT; - outliner_add_element(soops, lb, linestyle, te, 0, 0); - } - } - } + ViewLayer *view_layer; + FreestyleLineSet *lineset; + + for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { + for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) { + FreestyleLineStyle *linestyle = lineset->linestyle; + if (linestyle) { + linestyle->id.tag |= LIB_TAG_DOIT; + } + } + } + for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { + for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) { + FreestyleLineStyle *linestyle = lineset->linestyle; + if (linestyle) { + if (!(linestyle->id.tag & LIB_TAG_DOIT)) { + continue; + } + linestyle->id.tag &= ~LIB_TAG_DOIT; + outliner_add_element(soops, lb, linestyle, te, 0, 0); + } + } + } } #endif -static void outliner_add_scene_contents(SpaceOutliner *soops, ListBase *lb, Scene *sce, TreeElement *te) +static void outliner_add_scene_contents(SpaceOutliner *soops, + ListBase *lb, + Scene *sce, + TreeElement *te) { - /* View layers */ - TreeElement *ten = outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0); - ten->name = IFACE_("View Layers"); - - ViewLayer *view_layer; - for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { - TreeElement *tenlay = outliner_add_element(soops, &ten->subtree, sce, te, TSE_R_LAYER, 0); - tenlay->name = view_layer->name; - tenlay->directdata = view_layer; - } - - /* Collections */ - ten = outliner_add_element(soops, lb, &sce->id, te, TSE_SCENE_COLLECTION_BASE, 0); - ten->name = IFACE_("Scene Collection"); - outliner_add_collection_recursive(soops, sce->master_collection, ten); - - /* Objects */ - ten = outliner_add_element(soops, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0); - ten->name = IFACE_("Objects"); - FOREACH_SCENE_OBJECT_BEGIN(sce, ob) - { - outliner_add_element(soops, &ten->subtree, ob, NULL, 0, 0); - } - FOREACH_SCENE_OBJECT_END; - outliner_make_object_parent_hierarchy(&ten->subtree); - - /* Animation Data */ - if (outliner_animdata_test(sce->adt)) { - outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0); - } - + /* View layers */ + TreeElement *ten = outliner_add_element(soops, lb, sce, te, TSE_R_LAYER_BASE, 0); + ten->name = IFACE_("View Layers"); + + ViewLayer *view_layer; + for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { + TreeElement *tenlay = outliner_add_element(soops, &ten->subtree, sce, te, TSE_R_LAYER, 0); + tenlay->name = view_layer->name; + tenlay->directdata = view_layer; + } + + /* Collections */ + ten = outliner_add_element(soops, lb, &sce->id, te, TSE_SCENE_COLLECTION_BASE, 0); + ten->name = IFACE_("Scene Collection"); + outliner_add_collection_recursive(soops, sce->master_collection, ten); + + /* Objects */ + ten = outliner_add_element(soops, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0); + ten->name = IFACE_("Objects"); + FOREACH_SCENE_OBJECT_BEGIN (sce, ob) { + outliner_add_element(soops, &ten->subtree, ob, NULL, 0, 0); + } + FOREACH_SCENE_OBJECT_END; + outliner_make_object_parent_hierarchy(&ten->subtree); + + /* Animation Data */ + if (outliner_animdata_test(sce->adt)) { + outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0); + } } // can be inlined if necessary -static void outliner_add_object_contents(SpaceOutliner *soops, TreeElement *te, TreeStoreElem *tselem, Object *ob) +static void outliner_add_object_contents(SpaceOutliner *soops, + TreeElement *te, + TreeStoreElem *tselem, + Object *ob) { - if (outliner_animdata_test(ob->adt)) { - outliner_add_element(soops, &te->subtree, ob, te, TSE_ANIM_DATA, 0); - } - - outliner_add_element(soops, &te->subtree, ob->poselib, te, 0, 0); // XXX FIXME.. add a special type for this - - if (ob->proxy && !ID_IS_LINKED(ob)) { - outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0); - } - - outliner_add_element(soops, &te->subtree, ob->data, te, 0, 0); - - if (ob->pose) { - bArmature *arm = ob->data; - bPoseChannel *pchan; - TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_POSE_BASE, 0); - - tenla->name = IFACE_("Pose"); - - /* channels undefined in editmode, but we want the 'tenla' pose icon itself */ - if ((arm->edbo == NULL) && (ob->mode & OB_MODE_POSE)) { - TreeElement *ten; - int a = 0, const_index = 1000; /* ensure unique id for bone constraints */ - - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next, a++) { - ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSE_CHANNEL, a); - ten->name = pchan->name; - ten->directdata = pchan; - pchan->temp = (void *)ten; - - if (pchan->constraints.first) { - //Object *target; - bConstraint *con; - TreeElement *ten1; - TreeElement *tenla1 = outliner_add_element(soops, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0); - //char *str; - - tenla1->name = IFACE_("Constraints"); - for (con = pchan->constraints.first; con; con = con->next, const_index++) { - ten1 = outliner_add_element(soops, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index); + if (outliner_animdata_test(ob->adt)) { + outliner_add_element(soops, &te->subtree, ob, te, TSE_ANIM_DATA, 0); + } + + outliner_add_element( + soops, &te->subtree, ob->poselib, te, 0, 0); // XXX FIXME.. add a special type for this + + if (ob->proxy && !ID_IS_LINKED(ob)) { + outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0); + } + + outliner_add_element(soops, &te->subtree, ob->data, te, 0, 0); + + if (ob->pose) { + bArmature *arm = ob->data; + bPoseChannel *pchan; + TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_POSE_BASE, 0); + + tenla->name = IFACE_("Pose"); + + /* channels undefined in editmode, but we want the 'tenla' pose icon itself */ + if ((arm->edbo == NULL) && (ob->mode & OB_MODE_POSE)) { + TreeElement *ten; + int a = 0, const_index = 1000; /* ensure unique id for bone constraints */ + + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next, a++) { + ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_POSE_CHANNEL, a); + ten->name = pchan->name; + ten->directdata = pchan; + pchan->temp = (void *)ten; + + if (pchan->constraints.first) { + //Object *target; + bConstraint *con; + TreeElement *ten1; + TreeElement *tenla1 = outliner_add_element( + soops, &ten->subtree, ob, ten, TSE_CONSTRAINT_BASE, 0); + //char *str; + + tenla1->name = IFACE_("Constraints"); + for (con = pchan->constraints.first; con; con = con->next, const_index++) { + ten1 = outliner_add_element( + soops, &tenla1->subtree, ob, tenla1, TSE_CONSTRAINT, const_index); #if 0 /* disabled as it needs to be reworked for recoded constraints system */ - target = get_constraint_target(con, &str); - if (str && str[0]) ten1->name = str; - else if (target) ten1->name = target->id.name + 2; - else ten1->name = con->name; + target = get_constraint_target(con, &str); + if (str && str[0]) ten1->name = str; + else if (target) ten1->name = target->id.name + 2; + else ten1->name = con->name; #endif - ten1->name = con->name; - ten1->directdata = con; - /* possible add all other types links? */ - } - } - } - /* make hierarchy */ - ten = tenla->subtree.first; - while (ten) { - TreeElement *nten = ten->next, *par; - tselem = TREESTORE(ten); - if (tselem->type == TSE_POSE_CHANNEL) { - pchan = (bPoseChannel *)ten->directdata; - if (pchan->parent) { - BLI_remlink(&tenla->subtree, ten); - par = (TreeElement *)pchan->parent->temp; - BLI_addtail(&par->subtree, ten); - ten->parent = par; - } - } - ten = nten; - } - } - - /* Pose Groups */ - if (ob->pose->agroups.first) { - bActionGroup *agrp; - TreeElement *ten_bonegrp = outliner_add_element(soops, &te->subtree, ob, te, TSE_POSEGRP_BASE, 0); - int a = 0; - - ten_bonegrp->name = IFACE_("Bone Groups"); - for (agrp = ob->pose->agroups.first; agrp; agrp = agrp->next, a++) { - TreeElement *ten; - ten = outliner_add_element(soops, &ten_bonegrp->subtree, ob, ten_bonegrp, TSE_POSEGRP, a); - ten->name = agrp->name; - ten->directdata = agrp; - } - } - } - - for (int a = 0; a < ob->totcol; a++) { - outliner_add_element(soops, &te->subtree, ob->mat[a], te, 0, a); - } - - if (ob->constraints.first) { - //Object *target; - bConstraint *con; - TreeElement *ten; - TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0); - //char *str; - int a; - - tenla->name = IFACE_("Constraints"); - for (con = ob->constraints.first, a = 0; con; con = con->next, a++) { - ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, a); + ten1->name = con->name; + ten1->directdata = con; + /* possible add all other types links? */ + } + } + } + /* make hierarchy */ + ten = tenla->subtree.first; + while (ten) { + TreeElement *nten = ten->next, *par; + tselem = TREESTORE(ten); + if (tselem->type == TSE_POSE_CHANNEL) { + pchan = (bPoseChannel *)ten->directdata; + if (pchan->parent) { + BLI_remlink(&tenla->subtree, ten); + par = (TreeElement *)pchan->parent->temp; + BLI_addtail(&par->subtree, ten); + ten->parent = par; + } + } + ten = nten; + } + } + + /* Pose Groups */ + if (ob->pose->agroups.first) { + bActionGroup *agrp; + TreeElement *ten_bonegrp = outliner_add_element( + soops, &te->subtree, ob, te, TSE_POSEGRP_BASE, 0); + int a = 0; + + ten_bonegrp->name = IFACE_("Bone Groups"); + for (agrp = ob->pose->agroups.first; agrp; agrp = agrp->next, a++) { + TreeElement *ten; + ten = outliner_add_element(soops, &ten_bonegrp->subtree, ob, ten_bonegrp, TSE_POSEGRP, a); + ten->name = agrp->name; + ten->directdata = agrp; + } + } + } + + for (int a = 0; a < ob->totcol; a++) { + outliner_add_element(soops, &te->subtree, ob->mat[a], te, 0, a); + } + + if (ob->constraints.first) { + //Object *target; + bConstraint *con; + TreeElement *ten; + TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_CONSTRAINT_BASE, 0); + //char *str; + int a; + + tenla->name = IFACE_("Constraints"); + for (con = ob->constraints.first, a = 0; con; con = con->next, a++) { + ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_CONSTRAINT, a); #if 0 /* disabled due to constraints system targets recode... code here needs review */ - target = get_constraint_target(con, &str); - if (str && str[0]) ten->name = str; - else if (target) ten->name = target->id.name + 2; - else ten->name = con->name; + target = get_constraint_target(con, &str); + if (str && str[0]) ten->name = str; + else if (target) ten->name = target->id.name + 2; + else ten->name = con->name; #endif - ten->name = con->name; - ten->directdata = con; - /* possible add all other types links? */ - } - } - - if (ob->modifiers.first) { - ModifierData *md; - TreeElement *ten_mod = outliner_add_element(soops, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0); - int index; - - ten_mod->name = IFACE_("Modifiers"); - for (index = 0, md = ob->modifiers.first; md; index++, md = md->next) { - TreeElement *ten = outliner_add_element(soops, &ten_mod->subtree, ob, ten_mod, TSE_MODIFIER, index); - ten->name = md->name; - ten->directdata = md; - - if (md->type == eModifierType_Lattice) { - outliner_add_element(soops, &ten->subtree, ((LatticeModifierData *) md)->object, ten, TSE_LINKED_OB, 0); - } - else if (md->type == eModifierType_Curve) { - outliner_add_element(soops, &ten->subtree, ((CurveModifierData *) md)->object, ten, TSE_LINKED_OB, 0); - } - else if (md->type == eModifierType_Armature) { - outliner_add_element(soops, &ten->subtree, ((ArmatureModifierData *) md)->object, ten, TSE_LINKED_OB, 0); - } - else if (md->type == eModifierType_Hook) { - outliner_add_element(soops, &ten->subtree, ((HookModifierData *) md)->object, ten, TSE_LINKED_OB, 0); - } - else if (md->type == eModifierType_ParticleSystem) { - ParticleSystem *psys = ((ParticleSystemModifierData *) md)->psys; - TreeElement *ten_psys; - - ten_psys = outliner_add_element(soops, &ten->subtree, ob, te, TSE_LINKED_PSYS, 0); - ten_psys->directdata = psys; - ten_psys->name = psys->part->id.name + 2; - } - } - } - - /* vertex groups */ - if (ob->defbase.first) { - bDeformGroup *defgroup; - TreeElement *ten; - TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0); - int a; - - tenla->name = IFACE_("Vertex Groups"); - for (defgroup = ob->defbase.first, a = 0; defgroup; defgroup = defgroup->next, a++) { - ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_DEFGROUP, a); - ten->name = defgroup->name; - ten->directdata = defgroup; - } - } - - /* duplicated group */ - if (ob->instance_collection) { - outliner_add_element(soops, &te->subtree, ob->instance_collection, te, 0, 0); - } + ten->name = con->name; + ten->directdata = con; + /* possible add all other types links? */ + } + } + + if (ob->modifiers.first) { + ModifierData *md; + TreeElement *ten_mod = outliner_add_element(soops, &te->subtree, ob, te, TSE_MODIFIER_BASE, 0); + int index; + + ten_mod->name = IFACE_("Modifiers"); + for (index = 0, md = ob->modifiers.first; md; index++, md = md->next) { + TreeElement *ten = outliner_add_element( + soops, &ten_mod->subtree, ob, ten_mod, TSE_MODIFIER, index); + ten->name = md->name; + ten->directdata = md; + + if (md->type == eModifierType_Lattice) { + outliner_add_element( + soops, &ten->subtree, ((LatticeModifierData *)md)->object, ten, TSE_LINKED_OB, 0); + } + else if (md->type == eModifierType_Curve) { + outliner_add_element( + soops, &ten->subtree, ((CurveModifierData *)md)->object, ten, TSE_LINKED_OB, 0); + } + else if (md->type == eModifierType_Armature) { + outliner_add_element( + soops, &ten->subtree, ((ArmatureModifierData *)md)->object, ten, TSE_LINKED_OB, 0); + } + else if (md->type == eModifierType_Hook) { + outliner_add_element( + soops, &ten->subtree, ((HookModifierData *)md)->object, ten, TSE_LINKED_OB, 0); + } + else if (md->type == eModifierType_ParticleSystem) { + ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; + TreeElement *ten_psys; + + ten_psys = outliner_add_element(soops, &ten->subtree, ob, te, TSE_LINKED_PSYS, 0); + ten_psys->directdata = psys; + ten_psys->name = psys->part->id.name + 2; + } + } + } + + /* vertex groups */ + if (ob->defbase.first) { + bDeformGroup *defgroup; + TreeElement *ten; + TreeElement *tenla = outliner_add_element(soops, &te->subtree, ob, te, TSE_DEFGROUP_BASE, 0); + int a; + + tenla->name = IFACE_("Vertex Groups"); + for (defgroup = ob->defbase.first, a = 0; defgroup; defgroup = defgroup->next, a++) { + ten = outliner_add_element(soops, &tenla->subtree, ob, tenla, TSE_DEFGROUP, a); + ten->name = defgroup->name; + ten->directdata = defgroup; + } + } + + /* duplicated group */ + if (ob->instance_collection) { + outliner_add_element(soops, &te->subtree, ob->instance_collection, te, 0, 0); + } } - // can be inlined if necessary -static void outliner_add_id_contents(SpaceOutliner *soops, TreeElement *te, TreeStoreElem *tselem, ID *id) +static void outliner_add_id_contents(SpaceOutliner *soops, + TreeElement *te, + TreeStoreElem *tselem, + ID *id) { - /* tuck pointer back in object, to construct hierarchy */ - if (GS(id->name) == ID_OB) { - id->newid = (ID *)te; - } - - /* expand specific data always */ - switch (GS(id->name)) { - case ID_LI: - { - te->name = ((Library *)id)->name; - break; - } - case ID_SCE: - { - outliner_add_scene_contents(soops, &te->subtree, (Scene *)id, te); - break; - } - case ID_OB: - { - outliner_add_object_contents(soops, te, tselem, (Object *)id); - break; - } - case ID_ME: - { - Mesh *me = (Mesh *)id; - int a; - - if (outliner_animdata_test(me->adt)) { - outliner_add_element(soops, &te->subtree, me, te, TSE_ANIM_DATA, 0); - } - - outliner_add_element(soops, &te->subtree, me->key, te, 0, 0); - for (a = 0; a < me->totcol; a++) { - outliner_add_element(soops, &te->subtree, me->mat[a], te, 0, a); - } - /* could do tfaces with image links, but the images are not grouped nicely. - * would require going over all tfaces, sort images in use. etc... */ - break; - } - case ID_CU: - { - Curve *cu = (Curve *)id; - int a; - - if (outliner_animdata_test(cu->adt)) { - outliner_add_element(soops, &te->subtree, cu, te, TSE_ANIM_DATA, 0); - } - - for (a = 0; a < cu->totcol; a++) { - outliner_add_element(soops, &te->subtree, cu->mat[a], te, 0, a); - } - break; - } - case ID_MB: - { - MetaBall *mb = (MetaBall *)id; - int a; - - if (outliner_animdata_test(mb->adt)) { - outliner_add_element(soops, &te->subtree, mb, te, TSE_ANIM_DATA, 0); - } - - for (a = 0; a < mb->totcol; a++) { - outliner_add_element(soops, &te->subtree, mb->mat[a], te, 0, a); - } - break; - } - case ID_MA: - { - Material *ma = (Material *)id; - - if (outliner_animdata_test(ma->adt)) { - outliner_add_element(soops, &te->subtree, ma, te, TSE_ANIM_DATA, 0); - } - break; - } - case ID_TE: - { - Tex *tex = (Tex *)id; - - if (outliner_animdata_test(tex->adt)) { - outliner_add_element(soops, &te->subtree, tex, te, TSE_ANIM_DATA, 0); - } - outliner_add_element(soops, &te->subtree, tex->ima, te, 0, 0); - break; - } - case ID_CA: - { - Camera *ca = (Camera *)id; - - if (outliner_animdata_test(ca->adt)) { - outliner_add_element(soops, &te->subtree, ca, te, TSE_ANIM_DATA, 0); - } - break; - } - case ID_CF: - { - CacheFile *cache_file = (CacheFile *)id; - - if (outliner_animdata_test(cache_file->adt)) { - outliner_add_element(soops, &te->subtree, cache_file, te, TSE_ANIM_DATA, 0); - } - - break; - } - case ID_LA: - { - Light *la = (Light *)id; - - if (outliner_animdata_test(la->adt)) { - outliner_add_element(soops, &te->subtree, la, te, TSE_ANIM_DATA, 0); - } - break; - } - case ID_SPK: - { - Speaker *spk = (Speaker *)id; - - if (outliner_animdata_test(spk->adt)) { - outliner_add_element(soops, &te->subtree, spk, te, TSE_ANIM_DATA, 0); - } - break; - } - case ID_LP: - { - LightProbe *prb = (LightProbe *)id; - - if (outliner_animdata_test(prb->adt)) { - outliner_add_element(soops, &te->subtree, prb, te, TSE_ANIM_DATA, 0); - } - break; - } - case ID_WO: - { - World *wrld = (World *)id; - - if (outliner_animdata_test(wrld->adt)) { - outliner_add_element(soops, &te->subtree, wrld, te, TSE_ANIM_DATA, 0); - } - break; - } - case ID_KE: - { - Key *key = (Key *)id; - - if (outliner_animdata_test(key->adt)) { - outliner_add_element(soops, &te->subtree, key, te, TSE_ANIM_DATA, 0); - } - break; - } - case ID_AC: - { - // XXX do we want to be exposing the F-Curves here? - //bAction *act = (bAction *)id; - break; - } - case ID_AR: - { - bArmature *arm = (bArmature *)id; - int a = 0; - - if (outliner_animdata_test(arm->adt)) { - outliner_add_element(soops, &te->subtree, arm, te, TSE_ANIM_DATA, 0); - } - - if (arm->edbo) { - EditBone *ebone; - TreeElement *ten; - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next, a++) { - ten = outliner_add_element(soops, &te->subtree, id, te, TSE_EBONE, a); - ten->directdata = ebone; - ten->name = ebone->name; - ebone->temp.p = ten; - } - /* make hierarchy */ - ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp.p : NULL; - while (ten) { - TreeElement *nten = ten->next, *par; - ebone = (EditBone *)ten->directdata; - if (ebone->parent) { - BLI_remlink(&te->subtree, ten); - par = ebone->parent->temp.p; - BLI_addtail(&par->subtree, ten); - ten->parent = par; - } - ten = nten; - } - } - else { - /* do not extend Armature when we have posemode */ - tselem = TREESTORE(te->parent); - if (GS(tselem->id->name) == ID_OB && ((Object *)tselem->id)->mode & OB_MODE_POSE) { - /* pass */ - } - else { - Bone *curBone; - for (curBone = arm->bonebase.first; curBone; curBone = curBone->next) { - outliner_add_bone(soops, &te->subtree, id, curBone, te, &a); - } - } - } - break; - } - case ID_LS: - { - FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id; - int a; - - if (outliner_animdata_test(linestyle->adt)) { - outliner_add_element(soops, &te->subtree, linestyle, te, TSE_ANIM_DATA, 0); - } - - for (a = 0; a < MAX_MTEX; a++) { - if (linestyle->mtex[a]) { - outliner_add_element(soops, &te->subtree, linestyle->mtex[a]->tex, te, 0, a); - } - } - break; - } - case ID_GD: - { - bGPdata *gpd = (bGPdata *)id; - bGPDlayer *gpl; - int a = 0; - - if (outliner_animdata_test(gpd->adt)) { - outliner_add_element(soops, &te->subtree, gpd, te, TSE_ANIM_DATA, 0); - } - - // TODO: base element for layers? - for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) { - outliner_add_element(soops, &te->subtree, gpl, te, TSE_GP_LAYER, a); - a++; - } - break; - } - case ID_GR: - { - /* Don't expand for instances, creates too many elements. */ - if (!(te->parent && te->parent->idcode == ID_OB)) { - Collection *collection = (Collection *)id; - outliner_add_collection_recursive(soops, collection, te); - } - } - default: - break; - } + /* tuck pointer back in object, to construct hierarchy */ + if (GS(id->name) == ID_OB) { + id->newid = (ID *)te; + } + + /* expand specific data always */ + switch (GS(id->name)) { + case ID_LI: { + te->name = ((Library *)id)->name; + break; + } + case ID_SCE: { + outliner_add_scene_contents(soops, &te->subtree, (Scene *)id, te); + break; + } + case ID_OB: { + outliner_add_object_contents(soops, te, tselem, (Object *)id); + break; + } + case ID_ME: { + Mesh *me = (Mesh *)id; + int a; + + if (outliner_animdata_test(me->adt)) { + outliner_add_element(soops, &te->subtree, me, te, TSE_ANIM_DATA, 0); + } + + outliner_add_element(soops, &te->subtree, me->key, te, 0, 0); + for (a = 0; a < me->totcol; a++) { + outliner_add_element(soops, &te->subtree, me->mat[a], te, 0, a); + } + /* could do tfaces with image links, but the images are not grouped nicely. + * would require going over all tfaces, sort images in use. etc... */ + break; + } + case ID_CU: { + Curve *cu = (Curve *)id; + int a; + + if (outliner_animdata_test(cu->adt)) { + outliner_add_element(soops, &te->subtree, cu, te, TSE_ANIM_DATA, 0); + } + + for (a = 0; a < cu->totcol; a++) { + outliner_add_element(soops, &te->subtree, cu->mat[a], te, 0, a); + } + break; + } + case ID_MB: { + MetaBall *mb = (MetaBall *)id; + int a; + + if (outliner_animdata_test(mb->adt)) { + outliner_add_element(soops, &te->subtree, mb, te, TSE_ANIM_DATA, 0); + } + + for (a = 0; a < mb->totcol; a++) { + outliner_add_element(soops, &te->subtree, mb->mat[a], te, 0, a); + } + break; + } + case ID_MA: { + Material *ma = (Material *)id; + + if (outliner_animdata_test(ma->adt)) { + outliner_add_element(soops, &te->subtree, ma, te, TSE_ANIM_DATA, 0); + } + break; + } + case ID_TE: { + Tex *tex = (Tex *)id; + + if (outliner_animdata_test(tex->adt)) { + outliner_add_element(soops, &te->subtree, tex, te, TSE_ANIM_DATA, 0); + } + outliner_add_element(soops, &te->subtree, tex->ima, te, 0, 0); + break; + } + case ID_CA: { + Camera *ca = (Camera *)id; + + if (outliner_animdata_test(ca->adt)) { + outliner_add_element(soops, &te->subtree, ca, te, TSE_ANIM_DATA, 0); + } + break; + } + case ID_CF: { + CacheFile *cache_file = (CacheFile *)id; + + if (outliner_animdata_test(cache_file->adt)) { + outliner_add_element(soops, &te->subtree, cache_file, te, TSE_ANIM_DATA, 0); + } + + break; + } + case ID_LA: { + Light *la = (Light *)id; + + if (outliner_animdata_test(la->adt)) { + outliner_add_element(soops, &te->subtree, la, te, TSE_ANIM_DATA, 0); + } + break; + } + case ID_SPK: { + Speaker *spk = (Speaker *)id; + + if (outliner_animdata_test(spk->adt)) { + outliner_add_element(soops, &te->subtree, spk, te, TSE_ANIM_DATA, 0); + } + break; + } + case ID_LP: { + LightProbe *prb = (LightProbe *)id; + + if (outliner_animdata_test(prb->adt)) { + outliner_add_element(soops, &te->subtree, prb, te, TSE_ANIM_DATA, 0); + } + break; + } + case ID_WO: { + World *wrld = (World *)id; + + if (outliner_animdata_test(wrld->adt)) { + outliner_add_element(soops, &te->subtree, wrld, te, TSE_ANIM_DATA, 0); + } + break; + } + case ID_KE: { + Key *key = (Key *)id; + + if (outliner_animdata_test(key->adt)) { + outliner_add_element(soops, &te->subtree, key, te, TSE_ANIM_DATA, 0); + } + break; + } + case ID_AC: { + // XXX do we want to be exposing the F-Curves here? + //bAction *act = (bAction *)id; + break; + } + case ID_AR: { + bArmature *arm = (bArmature *)id; + int a = 0; + + if (outliner_animdata_test(arm->adt)) { + outliner_add_element(soops, &te->subtree, arm, te, TSE_ANIM_DATA, 0); + } + + if (arm->edbo) { + EditBone *ebone; + TreeElement *ten; + + for (ebone = arm->edbo->first; ebone; ebone = ebone->next, a++) { + ten = outliner_add_element(soops, &te->subtree, id, te, TSE_EBONE, a); + ten->directdata = ebone; + ten->name = ebone->name; + ebone->temp.p = ten; + } + /* make hierarchy */ + ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp.p : NULL; + while (ten) { + TreeElement *nten = ten->next, *par; + ebone = (EditBone *)ten->directdata; + if (ebone->parent) { + BLI_remlink(&te->subtree, ten); + par = ebone->parent->temp.p; + BLI_addtail(&par->subtree, ten); + ten->parent = par; + } + ten = nten; + } + } + else { + /* do not extend Armature when we have posemode */ + tselem = TREESTORE(te->parent); + if (GS(tselem->id->name) == ID_OB && ((Object *)tselem->id)->mode & OB_MODE_POSE) { + /* pass */ + } + else { + Bone *curBone; + for (curBone = arm->bonebase.first; curBone; curBone = curBone->next) { + outliner_add_bone(soops, &te->subtree, id, curBone, te, &a); + } + } + } + break; + } + case ID_LS: { + FreestyleLineStyle *linestyle = (FreestyleLineStyle *)id; + int a; + + if (outliner_animdata_test(linestyle->adt)) { + outliner_add_element(soops, &te->subtree, linestyle, te, TSE_ANIM_DATA, 0); + } + + for (a = 0; a < MAX_MTEX; a++) { + if (linestyle->mtex[a]) { + outliner_add_element(soops, &te->subtree, linestyle->mtex[a]->tex, te, 0, a); + } + } + break; + } + case ID_GD: { + bGPdata *gpd = (bGPdata *)id; + bGPDlayer *gpl; + int a = 0; + + if (outliner_animdata_test(gpd->adt)) { + outliner_add_element(soops, &te->subtree, gpd, te, TSE_ANIM_DATA, 0); + } + + // TODO: base element for layers? + for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) { + outliner_add_element(soops, &te->subtree, gpl, te, TSE_GP_LAYER, a); + a++; + } + break; + } + case ID_GR: { + /* Don't expand for instances, creates too many elements. */ + if (!(te->parent && te->parent->idcode == ID_OB)) { + Collection *collection = (Collection *)id; + outliner_add_collection_recursive(soops, collection, te); + } + } + default: + break; + } } // TODO: this function needs to be split up! It's getting a bit too large... // Note: "ID" is not always a real ID -static TreeElement *outliner_add_element(SpaceOutliner *soops, ListBase *lb, void *idv, - TreeElement *parent, short type, short index) +static TreeElement *outliner_add_element( + SpaceOutliner *soops, ListBase *lb, void *idv, TreeElement *parent, short type, short index) { - TreeElement *te; - TreeStoreElem *tselem; - ID *id = idv; - - if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { - id = ((PointerRNA *)idv)->id.data; - if (!id) { - id = ((PointerRNA *)idv)->data; - } - } - else if (type == TSE_GP_LAYER) { - /* idv is the layer its self */ - id = TREESTORE(parent)->id; - } - - /* exceptions */ - if (type == TSE_ID_BASE) { - /* pass */ - } - else if (id == NULL) { - return NULL; - } - - if (type == 0) { - /* Zero type means real ID, ensure we do not get non-outliner ID types here... */ - BLI_assert(TREESTORE_ID_TYPE(id)); - } - - te = MEM_callocN(sizeof(TreeElement), "tree elem"); - /* add to the visual tree */ - BLI_addtail(lb, te); - /* add to the storage */ - check_persistent(soops, te, id, type, index); - tselem = TREESTORE(te); - - /* if we are searching for something expand to see child elements */ - if (SEARCHING_OUTLINER(soops)) { - tselem->flag |= TSE_CHILDSEARCH; - } - - te->parent = parent; - te->index = index; // for data arrays - if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { - /* pass */ - } - else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { - /* pass */ - } - else if (type == TSE_ANIM_DATA) { - /* pass */ - } - else if (type == TSE_GP_LAYER) { - /* pass */ - } - else if (ELEM(type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { - /* pass */ - } - else if (type == TSE_ID_BASE) { - /* pass */ - } - else { - /* do here too, for blend file viewer, own ID_LI then shows file name */ - if (GS(id->name) == ID_LI) { - te->name = ((Library *)id)->name; - } - else { - te->name = id->name + 2; // default, can be overridden by Library or non-ID data - } - te->idcode = GS(id->name); - } - - if (type == 0) { - TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL; - - /* ID datablock */ - if (tsepar == NULL || tsepar->type != TSE_ID_BASE || soops->filter_id_type) { - outliner_add_id_contents(soops, te, tselem, id); - } - } - else if (type == TSE_ANIM_DATA) { - IdAdtTemplate *iat = (IdAdtTemplate *)idv; - AnimData *adt = (AnimData *)iat->adt; - - /* this element's info */ - te->name = IFACE_("Animation"); - te->directdata = adt; - - /* Action */ - outliner_add_element(soops, &te->subtree, adt->action, te, 0, 0); - - /* Drivers */ - if (adt->drivers.first) { - TreeElement *ted = outliner_add_element(soops, &te->subtree, adt, te, TSE_DRIVER_BASE, 0); - ID *lastadded = NULL; - FCurve *fcu; - - ted->name = IFACE_("Drivers"); - - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - if (fcu->driver && fcu->driver->variables.first) { - ChannelDriver *driver = fcu->driver; - DriverVar *dvar; - - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { - /* loop over all targets used here */ - DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar) - { - if (lastadded != dtar->id) { - // XXX this lastadded check is rather lame, and also fails quite badly... - outliner_add_element(soops, &ted->subtree, dtar->id, ted, TSE_LINKED_OB, 0); - lastadded = dtar->id; - } - } - DRIVER_TARGETS_LOOPER_END; - } - } - } - } - - /* NLA Data */ - if (adt->nla_tracks.first) { - TreeElement *tenla = outliner_add_element(soops, &te->subtree, adt, te, TSE_NLA, 0); - NlaTrack *nlt; - int a = 0; - - tenla->name = IFACE_("NLA Tracks"); - - for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { - TreeElement *tenlt = outliner_add_element(soops, &tenla->subtree, nlt, tenla, TSE_NLA_TRACK, a); - NlaStrip *strip; - TreeElement *ten; - int b = 0; - - tenlt->name = nlt->name; - - for (strip = nlt->strips.first; strip; strip = strip->next, b++) { - ten = outliner_add_element(soops, &tenlt->subtree, strip->act, tenlt, TSE_NLA_ACTION, b); - if (ten) { - ten->directdata = strip; - } - } - } - } - } - else if (type == TSE_GP_LAYER) { - bGPDlayer *gpl = (bGPDlayer *)idv; - - te->name = gpl->info; - te->directdata = gpl; - } - else if (type == TSE_SEQUENCE) { - Sequence *seq = (Sequence *) idv; - Sequence *p; - - /* - * The idcode is a little hack, but the outliner - * only check te->idcode if te->type is equal to zero, - * so this is "safe". - */ - te->idcode = seq->type; - te->directdata = seq; - te->name = seq->name + 2; - - if (!(seq->type & SEQ_TYPE_EFFECT)) { - /* - * This work like the sequence. - * If the sequence have a name (not default name) - * show it, in other case put the filename. - */ - - if (seq->type == SEQ_TYPE_META) { - p = seq->seqbase.first; - while (p) { - outliner_add_element(soops, &te->subtree, (void *)p, te, TSE_SEQUENCE, index); - p = p->next; - } - } - else { - outliner_add_element(soops, &te->subtree, (void *)seq->strip, te, TSE_SEQ_STRIP, index); - } - } - } - else if (type == TSE_SEQ_STRIP) { - Strip *strip = (Strip *)idv; - - if (strip->dir[0] != '\0') { - te->name = strip->dir; - } - else { - te->name = IFACE_("Strip None"); - } - te->directdata = strip; - } - else if (type == TSE_SEQUENCE_DUP) { - Sequence *seq = (Sequence *)idv; - - te->idcode = seq->type; - te->directdata = seq; - te->name = seq->strip->stripdata->name; - } - else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { - PointerRNA pptr, propptr, *ptr = (PointerRNA *)idv; - PropertyRNA *prop, *iterprop; - PropertyType proptype; - - /* Don't display arrays larger, weak but index is stored as a short, - * also the outliner isn't intended for editing such large data-sets. */ - BLI_STATIC_ASSERT(sizeof(te->index) == 2, "Index is no longer short!"); - const int tot_limit = SHRT_MAX; - - int a, tot; - - /* we do lazy build, for speed and to avoid infinite recursion */ - - if (ptr->data == NULL) { - te->name = IFACE_("(empty)"); - } - else if (type == TSE_RNA_STRUCT) { - /* struct */ - te->name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL); - - if (te->name) { - te->flag |= TE_FREE_NAME; - } - else { - te->name = RNA_struct_ui_name(ptr->type); - } - - /* If searching don't expand RNA entries */ - if (SEARCHING_OUTLINER(soops) && BLI_strcasecmp("RNA", te->name) == 0) { - tselem->flag &= ~TSE_CHILDSEARCH; - } - - iterprop = RNA_struct_iterator_property(ptr->type); - tot = RNA_property_collection_length(ptr, iterprop); - CLAMP_MAX(tot, tot_limit); - - /* auto open these cases */ - if (!parent || (RNA_property_type(parent->directdata)) == PROP_POINTER) { - if (!tselem->used) { - tselem->flag &= ~TSE_CLOSED; - } - } - - if (TSELEM_OPEN(tselem, soops)) { - for (a = 0; a < tot; a++) { - RNA_property_collection_lookup_int(ptr, iterprop, a, &propptr); - if (!(RNA_property_flag(propptr.data) & PROP_HIDDEN)) { - outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a); - } - } - } - else if (tot) { - te->flag |= TE_LAZY_CLOSED; - } - - te->rnaptr = *ptr; - } - else if (type == TSE_RNA_PROPERTY) { - /* property */ - iterprop = RNA_struct_iterator_property(ptr->type); - RNA_property_collection_lookup_int(ptr, iterprop, index, &propptr); - - prop = propptr.data; - proptype = RNA_property_type(prop); - - te->name = RNA_property_ui_name(prop); - te->directdata = prop; - te->rnaptr = *ptr; - - /* If searching don't expand RNA entries */ - if (SEARCHING_OUTLINER(soops) && BLI_strcasecmp("RNA", te->name) == 0) { - tselem->flag &= ~TSE_CHILDSEARCH; - } - - if (proptype == PROP_POINTER) { - pptr = RNA_property_pointer_get(ptr, prop); - - if (pptr.data) { - if (TSELEM_OPEN(tselem, soops)) { - outliner_add_element(soops, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, -1); - } - else { - te->flag |= TE_LAZY_CLOSED; - } - } - } - else if (proptype == PROP_COLLECTION) { - tot = RNA_property_collection_length(ptr, prop); - CLAMP_MAX(tot, tot_limit); - - if (TSELEM_OPEN(tselem, soops)) { - for (a = 0; a < tot; a++) { - RNA_property_collection_lookup_int(ptr, prop, a, &pptr); - outliner_add_element(soops, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, a); - } - } - else if (tot) { - te->flag |= TE_LAZY_CLOSED; - } - } - else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { - tot = RNA_property_array_length(ptr, prop); - CLAMP_MAX(tot, tot_limit); - - if (TSELEM_OPEN(tselem, soops)) { - for (a = 0; a < tot; a++) { - outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_ARRAY_ELEM, a); - } - } - else if (tot) { - te->flag |= TE_LAZY_CLOSED; - } - } - } - else if (type == TSE_RNA_ARRAY_ELEM) { - char c; - - prop = parent->directdata; - - te->directdata = prop; - te->rnaptr = *ptr; - te->index = index; - - c = RNA_property_array_item_char(prop, index); - - te->name = MEM_callocN(sizeof(char) * 20, "OutlinerRNAArrayName"); - if (c) { - sprintf((char *)te->name, " %c", c); - } - else { - sprintf((char *)te->name, " %d", index + 1); - } - te->flag |= TE_FREE_NAME; - } - } - else if (type == TSE_KEYMAP) { - wmKeyMap *km = (wmKeyMap *)idv; - wmKeyMapItem *kmi; - char opname[OP_MAX_TYPENAME]; - - te->directdata = idv; - te->name = km->idname; - - if (TSELEM_OPEN(tselem, soops)) { - int a = 0; - - for (kmi = km->items.first; kmi; kmi = kmi->next, a++) { - const char *key = WM_key_event_string(kmi->type, false); - - if (key[0]) { - wmOperatorType *ot = NULL; - - if (kmi->propvalue) { - /* pass */ - } - else { - ot = WM_operatortype_find(kmi->idname, 0); - } - - if (ot || kmi->propvalue) { - TreeElement *ten = outliner_add_element(soops, &te->subtree, kmi, te, TSE_KEYMAP_ITEM, a); - - ten->directdata = kmi; - - if (kmi->propvalue) { - ten->name = IFACE_("Modal map, not yet"); - } - else { - WM_operator_py_idname(opname, ot->idname); - ten->name = BLI_strdup(opname); - ten->flag |= TE_FREE_NAME; - } - } - } - } - } - else { - te->flag |= TE_LAZY_CLOSED; - } - } - - return te; + TreeElement *te; + TreeStoreElem *tselem; + ID *id = idv; + + if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { + id = ((PointerRNA *)idv)->id.data; + if (!id) { + id = ((PointerRNA *)idv)->data; + } + } + else if (type == TSE_GP_LAYER) { + /* idv is the layer its self */ + id = TREESTORE(parent)->id; + } + + /* exceptions */ + if (type == TSE_ID_BASE) { + /* pass */ + } + else if (id == NULL) { + return NULL; + } + + if (type == 0) { + /* Zero type means real ID, ensure we do not get non-outliner ID types here... */ + BLI_assert(TREESTORE_ID_TYPE(id)); + } + + te = MEM_callocN(sizeof(TreeElement), "tree elem"); + /* add to the visual tree */ + BLI_addtail(lb, te); + /* add to the storage */ + check_persistent(soops, te, id, type, index); + tselem = TREESTORE(te); + + /* if we are searching for something expand to see child elements */ + if (SEARCHING_OUTLINER(soops)) { + tselem->flag |= TSE_CHILDSEARCH; + } + + te->parent = parent; + te->index = index; // for data arrays + if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { + /* pass */ + } + else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { + /* pass */ + } + else if (type == TSE_ANIM_DATA) { + /* pass */ + } + else if (type == TSE_GP_LAYER) { + /* pass */ + } + else if (ELEM(type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { + /* pass */ + } + else if (type == TSE_ID_BASE) { + /* pass */ + } + else { + /* do here too, for blend file viewer, own ID_LI then shows file name */ + if (GS(id->name) == ID_LI) { + te->name = ((Library *)id)->name; + } + else { + te->name = id->name + 2; // default, can be overridden by Library or non-ID data + } + te->idcode = GS(id->name); + } + + if (type == 0) { + TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL; + + /* ID datablock */ + if (tsepar == NULL || tsepar->type != TSE_ID_BASE || soops->filter_id_type) { + outliner_add_id_contents(soops, te, tselem, id); + } + } + else if (type == TSE_ANIM_DATA) { + IdAdtTemplate *iat = (IdAdtTemplate *)idv; + AnimData *adt = (AnimData *)iat->adt; + + /* this element's info */ + te->name = IFACE_("Animation"); + te->directdata = adt; + + /* Action */ + outliner_add_element(soops, &te->subtree, adt->action, te, 0, 0); + + /* Drivers */ + if (adt->drivers.first) { + TreeElement *ted = outliner_add_element(soops, &te->subtree, adt, te, TSE_DRIVER_BASE, 0); + ID *lastadded = NULL; + FCurve *fcu; + + ted->name = IFACE_("Drivers"); + + for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { + if (fcu->driver && fcu->driver->variables.first) { + ChannelDriver *driver = fcu->driver; + DriverVar *dvar; + + for (dvar = driver->variables.first; dvar; dvar = dvar->next) { + /* loop over all targets used here */ + DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) { + if (lastadded != dtar->id) { + // XXX this lastadded check is rather lame, and also fails quite badly... + outliner_add_element(soops, &ted->subtree, dtar->id, ted, TSE_LINKED_OB, 0); + lastadded = dtar->id; + } + } + DRIVER_TARGETS_LOOPER_END; + } + } + } + } + + /* NLA Data */ + if (adt->nla_tracks.first) { + TreeElement *tenla = outliner_add_element(soops, &te->subtree, adt, te, TSE_NLA, 0); + NlaTrack *nlt; + int a = 0; + + tenla->name = IFACE_("NLA Tracks"); + + for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) { + TreeElement *tenlt = outliner_add_element( + soops, &tenla->subtree, nlt, tenla, TSE_NLA_TRACK, a); + NlaStrip *strip; + TreeElement *ten; + int b = 0; + + tenlt->name = nlt->name; + + for (strip = nlt->strips.first; strip; strip = strip->next, b++) { + ten = outliner_add_element(soops, &tenlt->subtree, strip->act, tenlt, TSE_NLA_ACTION, b); + if (ten) { + ten->directdata = strip; + } + } + } + } + } + else if (type == TSE_GP_LAYER) { + bGPDlayer *gpl = (bGPDlayer *)idv; + + te->name = gpl->info; + te->directdata = gpl; + } + else if (type == TSE_SEQUENCE) { + Sequence *seq = (Sequence *)idv; + Sequence *p; + + /* + * The idcode is a little hack, but the outliner + * only check te->idcode if te->type is equal to zero, + * so this is "safe". + */ + te->idcode = seq->type; + te->directdata = seq; + te->name = seq->name + 2; + + if (!(seq->type & SEQ_TYPE_EFFECT)) { + /* + * This work like the sequence. + * If the sequence have a name (not default name) + * show it, in other case put the filename. + */ + + if (seq->type == SEQ_TYPE_META) { + p = seq->seqbase.first; + while (p) { + outliner_add_element(soops, &te->subtree, (void *)p, te, TSE_SEQUENCE, index); + p = p->next; + } + } + else { + outliner_add_element(soops, &te->subtree, (void *)seq->strip, te, TSE_SEQ_STRIP, index); + } + } + } + else if (type == TSE_SEQ_STRIP) { + Strip *strip = (Strip *)idv; + + if (strip->dir[0] != '\0') { + te->name = strip->dir; + } + else { + te->name = IFACE_("Strip None"); + } + te->directdata = strip; + } + else if (type == TSE_SEQUENCE_DUP) { + Sequence *seq = (Sequence *)idv; + + te->idcode = seq->type; + te->directdata = seq; + te->name = seq->strip->stripdata->name; + } + else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { + PointerRNA pptr, propptr, *ptr = (PointerRNA *)idv; + PropertyRNA *prop, *iterprop; + PropertyType proptype; + + /* Don't display arrays larger, weak but index is stored as a short, + * also the outliner isn't intended for editing such large data-sets. */ + BLI_STATIC_ASSERT(sizeof(te->index) == 2, "Index is no longer short!"); + const int tot_limit = SHRT_MAX; + + int a, tot; + + /* we do lazy build, for speed and to avoid infinite recursion */ + + if (ptr->data == NULL) { + te->name = IFACE_("(empty)"); + } + else if (type == TSE_RNA_STRUCT) { + /* struct */ + te->name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL); + + if (te->name) { + te->flag |= TE_FREE_NAME; + } + else { + te->name = RNA_struct_ui_name(ptr->type); + } + + /* If searching don't expand RNA entries */ + if (SEARCHING_OUTLINER(soops) && BLI_strcasecmp("RNA", te->name) == 0) { + tselem->flag &= ~TSE_CHILDSEARCH; + } + + iterprop = RNA_struct_iterator_property(ptr->type); + tot = RNA_property_collection_length(ptr, iterprop); + CLAMP_MAX(tot, tot_limit); + + /* auto open these cases */ + if (!parent || (RNA_property_type(parent->directdata)) == PROP_POINTER) { + if (!tselem->used) { + tselem->flag &= ~TSE_CLOSED; + } + } + + if (TSELEM_OPEN(tselem, soops)) { + for (a = 0; a < tot; a++) { + RNA_property_collection_lookup_int(ptr, iterprop, a, &propptr); + if (!(RNA_property_flag(propptr.data) & PROP_HIDDEN)) { + outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a); + } + } + } + else if (tot) { + te->flag |= TE_LAZY_CLOSED; + } + + te->rnaptr = *ptr; + } + else if (type == TSE_RNA_PROPERTY) { + /* property */ + iterprop = RNA_struct_iterator_property(ptr->type); + RNA_property_collection_lookup_int(ptr, iterprop, index, &propptr); + + prop = propptr.data; + proptype = RNA_property_type(prop); + + te->name = RNA_property_ui_name(prop); + te->directdata = prop; + te->rnaptr = *ptr; + + /* If searching don't expand RNA entries */ + if (SEARCHING_OUTLINER(soops) && BLI_strcasecmp("RNA", te->name) == 0) { + tselem->flag &= ~TSE_CHILDSEARCH; + } + + if (proptype == PROP_POINTER) { + pptr = RNA_property_pointer_get(ptr, prop); + + if (pptr.data) { + if (TSELEM_OPEN(tselem, soops)) { + outliner_add_element(soops, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, -1); + } + else { + te->flag |= TE_LAZY_CLOSED; + } + } + } + else if (proptype == PROP_COLLECTION) { + tot = RNA_property_collection_length(ptr, prop); + CLAMP_MAX(tot, tot_limit); + + if (TSELEM_OPEN(tselem, soops)) { + for (a = 0; a < tot; a++) { + RNA_property_collection_lookup_int(ptr, prop, a, &pptr); + outliner_add_element(soops, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, a); + } + } + else if (tot) { + te->flag |= TE_LAZY_CLOSED; + } + } + else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { + tot = RNA_property_array_length(ptr, prop); + CLAMP_MAX(tot, tot_limit); + + if (TSELEM_OPEN(tselem, soops)) { + for (a = 0; a < tot; a++) { + outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_ARRAY_ELEM, a); + } + } + else if (tot) { + te->flag |= TE_LAZY_CLOSED; + } + } + } + else if (type == TSE_RNA_ARRAY_ELEM) { + char c; + + prop = parent->directdata; + + te->directdata = prop; + te->rnaptr = *ptr; + te->index = index; + + c = RNA_property_array_item_char(prop, index); + + te->name = MEM_callocN(sizeof(char) * 20, "OutlinerRNAArrayName"); + if (c) { + sprintf((char *)te->name, " %c", c); + } + else { + sprintf((char *)te->name, " %d", index + 1); + } + te->flag |= TE_FREE_NAME; + } + } + else if (type == TSE_KEYMAP) { + wmKeyMap *km = (wmKeyMap *)idv; + wmKeyMapItem *kmi; + char opname[OP_MAX_TYPENAME]; + + te->directdata = idv; + te->name = km->idname; + + if (TSELEM_OPEN(tselem, soops)) { + int a = 0; + + for (kmi = km->items.first; kmi; kmi = kmi->next, a++) { + const char *key = WM_key_event_string(kmi->type, false); + + if (key[0]) { + wmOperatorType *ot = NULL; + + if (kmi->propvalue) { + /* pass */ + } + else { + ot = WM_operatortype_find(kmi->idname, 0); + } + + if (ot || kmi->propvalue) { + TreeElement *ten = outliner_add_element( + soops, &te->subtree, kmi, te, TSE_KEYMAP_ITEM, a); + + ten->directdata = kmi; + + if (kmi->propvalue) { + ten->name = IFACE_("Modal map, not yet"); + } + else { + WM_operator_py_idname(opname, ot->idname); + ten->name = BLI_strdup(opname); + ten->flag |= TE_FREE_NAME; + } + } + } + } + } + else { + te->flag |= TE_LAZY_CLOSED; + } + } + + return te; } /* ======================================================= */ @@ -1139,297 +1137,307 @@ static TreeElement *outliner_add_element(SpaceOutliner *soops, ListBase *lb, voi /* Helped function to put duplicate sequence in the same tree. */ static int need_add_seq_dup(Sequence *seq) { - Sequence *p; - - if ((!seq->strip) || (!seq->strip->stripdata)) { - return 1; - } - - /* - * First check backward, if we found a duplicate - * sequence before this, don't need it, just return. - */ - p = seq->prev; - while (p) { - if ((!p->strip) || (!p->strip->stripdata)) { - p = p->prev; - continue; - } - - if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) { - return 2; - } - p = p->prev; - } - - p = seq->next; - while (p) { - if ((!p->strip) || (!p->strip->stripdata)) { - p = p->next; - continue; - } - - if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) { - return 0; - } - p = p->next; - } - return(1); + Sequence *p; + + if ((!seq->strip) || (!seq->strip->stripdata)) { + return 1; + } + + /* + * First check backward, if we found a duplicate + * sequence before this, don't need it, just return. + */ + p = seq->prev; + while (p) { + if ((!p->strip) || (!p->strip->stripdata)) { + p = p->prev; + continue; + } + + if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) { + return 2; + } + p = p->prev; + } + + p = seq->next; + while (p) { + if ((!p->strip) || (!p->strip->stripdata)) { + p = p->next; + continue; + } + + if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) { + return 0; + } + p = p->next; + } + return (1); } static void outliner_add_seq_dup(SpaceOutliner *soops, Sequence *seq, TreeElement *te, short index) { - /* TreeElement *ch; */ /* UNUSED */ - Sequence *p; - - p = seq; - while (p) { - if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) { - p = p->next; - continue; - } - - if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) { - /* ch = */ /* UNUSED */ outliner_add_element(soops, &te->subtree, (void *)p, te, TSE_SEQUENCE, index); - } - p = p->next; - } + /* TreeElement *ch; */ /* UNUSED */ + Sequence *p; + + p = seq; + while (p) { + if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) { + p = p->next; + continue; + } + + if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name)) { + /* ch = */ /* UNUSED */ outliner_add_element( + soops, &te->subtree, (void *)p, te, TSE_SEQUENCE, index); + } + p = p->next; + } } - /* ----------------------------------------------- */ static const char *outliner_idcode_to_plural(short idcode) { - const char *propname = BKE_idcode_to_name_plural(idcode); - PropertyRNA *prop = RNA_struct_type_find_property(&RNA_BlendData, propname); - return (prop) ? RNA_property_ui_name(prop) : "UNKNOWN"; + const char *propname = BKE_idcode_to_name_plural(idcode); + PropertyRNA *prop = RNA_struct_type_find_property(&RNA_BlendData, propname); + return (prop) ? RNA_property_ui_name(prop) : "UNKNOWN"; } static bool outliner_library_id_show(Library *lib, ID *id, short filter_id_type) { - if (id->lib != lib) { - return false; - } - - if (filter_id_type == ID_GR) { - /* Don't show child collections of non-scene master collection, - * they are already shown as children. */ - Collection *collection = (Collection *)id; - 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) { - return false; - } - } - - return true; + if (id->lib != lib) { + return false; + } + + if (filter_id_type == ID_GR) { + /* Don't show child collections of non-scene master collection, + * they are already shown as children. */ + Collection *collection = (Collection *)id; + 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) { + return false; + } + } + + return true; } -static TreeElement *outliner_add_library_contents(Main *mainvar, SpaceOutliner *soops, ListBase *lb, Library *lib) +static TreeElement *outliner_add_library_contents(Main *mainvar, + SpaceOutliner *soops, + ListBase *lb, + Library *lib) { - TreeElement *ten, *tenlib = NULL; - ListBase *lbarray[MAX_LIBARRAY]; - int a, tot; - short filter_id_type = (soops->filter & SO_FILTER_ID_TYPE) ? soops->filter_id_type : 0; - - if (filter_id_type) { - lbarray[0] = which_libbase(mainvar, soops->filter_id_type); - tot = 1; - } - else { - tot = set_listbasepointers(mainvar, lbarray); - } - - for (a = 0; a < tot; a++) { - if (lbarray[a] && lbarray[a]->first) { - ID *id = lbarray[a]->first; - - /* check if there's data in current lib */ - for (; id; id = id->next) { - if (id->lib == lib) { - break; - } - } - - if (id) { - if (!tenlib) { - /* Create library tree element on demand, depending if there are any datablocks. */ - if (lib) { - tenlib = outliner_add_element(soops, lb, lib, NULL, 0, 0); - } - else { - tenlib = outliner_add_element(soops, lb, mainvar, NULL, TSE_ID_BASE, 0); - tenlib->name = IFACE_("Current File"); - } - } - - /* Create datablock list parent element on demand. */ - if (filter_id_type) { - ten = tenlib; - } - else { - ten = outliner_add_element(soops, &tenlib->subtree, lbarray[a], NULL, TSE_ID_BASE, 0); - ten->directdata = lbarray[a]; - ten->name = outliner_idcode_to_plural(GS(id->name)); - } - - for (id = lbarray[a]->first; id; id = id->next) { - if (outliner_library_id_show(lib, id, filter_id_type)) { - outliner_add_element(soops, &ten->subtree, id, ten, 0, 0); - } - } - } - } - } - - return tenlib; + TreeElement *ten, *tenlib = NULL; + ListBase *lbarray[MAX_LIBARRAY]; + int a, tot; + short filter_id_type = (soops->filter & SO_FILTER_ID_TYPE) ? soops->filter_id_type : 0; + + if (filter_id_type) { + lbarray[0] = which_libbase(mainvar, soops->filter_id_type); + tot = 1; + } + else { + tot = set_listbasepointers(mainvar, lbarray); + } + + for (a = 0; a < tot; a++) { + if (lbarray[a] && lbarray[a]->first) { + ID *id = lbarray[a]->first; + + /* check if there's data in current lib */ + for (; id; id = id->next) { + if (id->lib == lib) { + break; + } + } + + if (id) { + if (!tenlib) { + /* Create library tree element on demand, depending if there are any datablocks. */ + if (lib) { + tenlib = outliner_add_element(soops, lb, lib, NULL, 0, 0); + } + else { + tenlib = outliner_add_element(soops, lb, mainvar, NULL, TSE_ID_BASE, 0); + tenlib->name = IFACE_("Current File"); + } + } + + /* Create datablock list parent element on demand. */ + if (filter_id_type) { + ten = tenlib; + } + else { + ten = outliner_add_element(soops, &tenlib->subtree, lbarray[a], NULL, TSE_ID_BASE, 0); + ten->directdata = lbarray[a]; + ten->name = outliner_idcode_to_plural(GS(id->name)); + } + + for (id = lbarray[a]->first; id; id = id->next) { + if (outliner_library_id_show(lib, id, filter_id_type)) { + outliner_add_element(soops, &ten->subtree, id, ten, 0, 0); + } + } + } + } + } + + return tenlib; } static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOutliner *soops) { - TreeElement *ten; - ListBase *lbarray[MAX_LIBARRAY]; - int a, tot; - short filter_id_type = (soops->filter & SO_FILTER_ID_TYPE) ? soops->filter_id_type : 0; - - if (filter_id_type) { - lbarray[0] = which_libbase(mainvar, soops->filter_id_type); - tot = 1; - } - else { - tot = set_listbasepointers(mainvar, lbarray); - } - - for (a = 0; a < tot; a++) { - if (lbarray[a] && lbarray[a]->first) { - ID *id = lbarray[a]->first; - - /* check if there are any datablocks of this type which are orphans */ - for (; id; id = id->next) { - if (ID_REAL_USERS(id) <= 0) { - break; - } - } - - if (id) { - /* header for this type of datablock */ - if (filter_id_type) { - ten = NULL; - } - else { - ten = outliner_add_element(soops, &soops->tree, lbarray[a], NULL, TSE_ID_BASE, 0); - ten->directdata = lbarray[a]; - ten->name = outliner_idcode_to_plural(GS(id->name)); - } - - /* add the orphaned datablocks - these will not be added with any subtrees attached */ - for (id = lbarray[a]->first; id; id = id->next) { - if (ID_REAL_USERS(id) <= 0) { - outliner_add_element(soops, (ten) ? &ten->subtree : &soops->tree, id, ten, 0, 0); - } - } - } - } - } + TreeElement *ten; + ListBase *lbarray[MAX_LIBARRAY]; + int a, tot; + short filter_id_type = (soops->filter & SO_FILTER_ID_TYPE) ? soops->filter_id_type : 0; + + if (filter_id_type) { + lbarray[0] = which_libbase(mainvar, soops->filter_id_type); + tot = 1; + } + else { + tot = set_listbasepointers(mainvar, lbarray); + } + + for (a = 0; a < tot; a++) { + if (lbarray[a] && lbarray[a]->first) { + ID *id = lbarray[a]->first; + + /* check if there are any datablocks of this type which are orphans */ + for (; id; id = id->next) { + if (ID_REAL_USERS(id) <= 0) { + break; + } + } + + if (id) { + /* header for this type of datablock */ + if (filter_id_type) { + ten = NULL; + } + else { + ten = outliner_add_element(soops, &soops->tree, lbarray[a], NULL, TSE_ID_BASE, 0); + ten->directdata = lbarray[a]; + ten->name = outliner_idcode_to_plural(GS(id->name)); + } + + /* add the orphaned datablocks - these will not be added with any subtrees attached */ + for (id = lbarray[a]->first; id; id = id->next) { + if (ID_REAL_USERS(id) <= 0) { + outliner_add_element(soops, (ten) ? &ten->subtree : &soops->tree, id, ten, 0, 0); + } + } + } + } + } } static void outliner_add_layer_collection_objects( - SpaceOutliner *soops, ListBase *tree, ViewLayer *layer, - LayerCollection *lc, TreeElement *ten) + SpaceOutliner *soops, ListBase *tree, ViewLayer *layer, LayerCollection *lc, TreeElement *ten) { - for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) { - Base *base = BKE_view_layer_base_find(layer, cob->ob); - TreeElement *te_object = outliner_add_element(soops, tree, base->object, ten, 0, 0); - te_object->directdata = base; - - if (!(base->flag & BASE_VISIBLE)) { - te_object->flag |= TE_DISABLED; - } - } + for (CollectionObject *cob = lc->collection->gobject.first; cob; cob = cob->next) { + Base *base = BKE_view_layer_base_find(layer, cob->ob); + TreeElement *te_object = outliner_add_element(soops, tree, base->object, ten, 0, 0); + te_object->directdata = base; + + if (!(base->flag & BASE_VISIBLE)) { + te_object->flag |= TE_DISABLED; + } + } } -static void outliner_add_layer_collections_recursive( - SpaceOutliner *soops, ListBase *tree, ViewLayer *layer, - ListBase *layer_collections, TreeElement *parent_ten, - const bool show_objects) +static void outliner_add_layer_collections_recursive(SpaceOutliner *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) { - ID *id = &lc->collection->id; - TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_LAYER_COLLECTION, 0); - - ten->name = id->name + 2; - ten->directdata = lc; - - /* Open by default. */ - TreeStoreElem *tselem = TREESTORE(ten); - if (!tselem->used) { - tselem->flag &= ~TSE_CLOSED; - } - - const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0; - if (exclude || - ((lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0)) - { - ten->flag |= TE_DISABLED; - } - - 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); - } - } + for (LayerCollection *lc = layer_collections->first; lc; lc = lc->next) { + ID *id = &lc->collection->id; + TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_LAYER_COLLECTION, 0); + + ten->name = id->name + 2; + ten->directdata = lc; + + /* Open by default. */ + TreeStoreElem *tselem = TREESTORE(ten); + if (!tselem->used) { + tselem->flag &= ~TSE_CLOSED; + } + + const bool exclude = (lc->flag & LAYER_COLLECTION_EXCLUDE) != 0; + if (exclude || ((lc->runtime_flag & LAYER_COLLECTION_VISIBLE) == 0)) { + ten->flag |= TE_DISABLED; + } + + 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); + } + } } -static void outliner_add_view_layer(SpaceOutliner *soops, ListBase *tree, TreeElement *parent, - ViewLayer *layer, const bool show_objects) +static void outliner_add_view_layer(SpaceOutliner *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); - } + /* 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) { - te->name = BKE_collection_ui_name_get(collection); - te->directdata = collection; + te->name = BKE_collection_ui_name_get(collection); + te->directdata = collection; } -BLI_INLINE void outliner_add_collection_objects( - SpaceOutliner *soops, ListBase *tree, Collection *collection, TreeElement *parent) +BLI_INLINE void outliner_add_collection_objects(SpaceOutliner *soops, + ListBase *tree, + Collection *collection, + TreeElement *parent) { - for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { - outliner_add_element(soops, tree, cob->ob, parent, 0, 0); - } + for (CollectionObject *cob = collection->gobject.first; cob; cob = cob->next) { + outliner_add_element(soops, tree, cob->ob, parent, 0, 0); + } } -static TreeElement *outliner_add_collection_recursive( - SpaceOutliner *soops, Collection *collection, TreeElement *ten) +static TreeElement *outliner_add_collection_recursive(SpaceOutliner *soops, + Collection *collection, + TreeElement *ten) { - outliner_add_collection_init(ten, collection); + outliner_add_collection_init(ten, collection); - for (CollectionChild *child = collection->children.first; child; child = child->next) { - outliner_add_element(soops, &ten->subtree, &child->collection->id, ten, 0, 0); - } + for (CollectionChild *child = collection->children.first; child; child = child->next) { + outliner_add_element(soops, &ten->subtree, &child->collection->id, ten, 0, 0); + } - if (soops->outlinevis != SO_SCENES) { - outliner_add_collection_objects(soops, &ten->subtree, collection, ten); - } + if (soops->outlinevis != SO_SCENES) { + outliner_add_collection_objects(soops, &ten->subtree, collection, ten); + } - return ten; + return ten; } /* ======================================================= */ @@ -1440,267 +1448,270 @@ static TreeElement *outliner_add_collection_recursive( /* make sure elements are correctly nested */ static void outliner_make_object_parent_hierarchy(ListBase *lb) { - TreeElement *te, *ten, *tep; - TreeStoreElem *tselem; - - /* build hierarchy */ - // XXX also, set extents here... - te = lb->first; - while (te) { - ten = te->next; - tselem = TREESTORE(te); - - if (tselem->type == 0 && te->idcode == ID_OB) { - Object *ob = (Object *)tselem->id; - if (ob->parent && ob->parent->id.newid) { - BLI_remlink(lb, te); - tep = (TreeElement *)ob->parent->id.newid; - BLI_addtail(&tep->subtree, te); - // set correct parent pointers - for (te = tep->subtree.first; te; te = te->next) { - te->parent = tep; - } - } - } - te = ten; - } + TreeElement *te, *ten, *tep; + TreeStoreElem *tselem; + + /* build hierarchy */ + // XXX also, set extents here... + te = lb->first; + while (te) { + ten = te->next; + tselem = TREESTORE(te); + + if (tselem->type == 0 && te->idcode == ID_OB) { + Object *ob = (Object *)tselem->id; + if (ob->parent && ob->parent->id.newid) { + BLI_remlink(lb, te); + tep = (TreeElement *)ob->parent->id.newid; + BLI_addtail(&tep->subtree, te); + // set correct parent pointers + for (te = tep->subtree.first; te; te = te->next) { + te->parent = tep; + } + } + } + te = ten; + } } /* Sorting ------------------------------------------------------ */ typedef struct tTreeSort { - TreeElement *te; - ID *id; - const char *name; - short idcode; + TreeElement *te; + ID *id; + const char *name; + short idcode; } tTreeSort; /* alphabetical comparator, tryping to put objects first */ static int treesort_alpha_ob(const void *v1, const void *v2) { - const tTreeSort *x1 = v1, *x2 = v2; - int comp; - - /* first put objects last (hierarchy) */ - comp = (x1->idcode == ID_OB); - if (x2->idcode == ID_OB) { - comp += 2; - } - - if (comp == 1) { - return 1; - } - else if (comp == 2) { - return -1; - } - else if (comp == 3) { - comp = strcmp(x1->name, x2->name); - - if (comp > 0) { - return 1; - } - else if (comp < 0) { - return -1; - } - return 0; - } - return 0; + const tTreeSort *x1 = v1, *x2 = v2; + int comp; + + /* first put objects last (hierarchy) */ + comp = (x1->idcode == ID_OB); + if (x2->idcode == ID_OB) { + comp += 2; + } + + if (comp == 1) { + return 1; + } + else if (comp == 2) { + return -1; + } + else if (comp == 3) { + comp = strcmp(x1->name, x2->name); + + if (comp > 0) { + return 1; + } + else if (comp < 0) { + return -1; + } + return 0; + } + return 0; } /* alphabetical comparator */ static int treesort_alpha(const void *v1, const void *v2) { - const tTreeSort *x1 = v1, *x2 = v2; - int comp; - - comp = strcmp(x1->name, x2->name); - - if (comp > 0) { - return 1; - } - else if (comp < 0) { - return -1; - } - return 0; + const tTreeSort *x1 = v1, *x2 = v2; + int comp; + + comp = strcmp(x1->name, x2->name); + + if (comp > 0) { + return 1; + } + else if (comp < 0) { + return -1; + } + return 0; } - /* this is nice option for later? doesn't look too useful... */ #if 0 static int treesort_obtype_alpha(const void *v1, const void *v2) { - const tTreeSort *x1 = v1, *x2 = v2; - - /* first put objects last (hierarchy) */ - if (x1->idcode == ID_OB && x2->idcode != ID_OB) { - return 1; - } - else if (x2->idcode == ID_OB && x1->idcode != ID_OB) { - return -1; - } - else { - /* 2nd we check ob type */ - if (x1->idcode == ID_OB && x2->idcode == ID_OB) { - if (((Object *)x1->id)->type > ((Object *)x2->id)->type) return 1; - else if (((Object *)x1->id)->type > ((Object *)x2->id)->type) return -1; - else return 0; - } - else { - int comp = strcmp(x1->name, x2->name); - - if (comp > 0) return 1; - else if (comp < 0) return -1; - return 0; - } - } + const tTreeSort *x1 = v1, *x2 = v2; + + /* first put objects last (hierarchy) */ + if (x1->idcode == ID_OB && x2->idcode != ID_OB) { + return 1; + } + else if (x2->idcode == ID_OB && x1->idcode != ID_OB) { + return -1; + } + else { + /* 2nd we check ob type */ + if (x1->idcode == ID_OB && x2->idcode == ID_OB) { + if (((Object *)x1->id)->type > ((Object *)x2->id)->type) return 1; + else if (((Object *)x1->id)->type > ((Object *)x2->id)->type) return -1; + else return 0; + } + else { + int comp = strcmp(x1->name, x2->name); + + if (comp > 0) return 1; + else if (comp < 0) return -1; + return 0; + } + } } #endif /* sort happens on each subtree individual */ static void outliner_sort(ListBase *lb) { - TreeElement *te; - TreeStoreElem *tselem; - - te = lb->last; - if (te == NULL) { - return; - } - tselem = TREESTORE(te); - - /* sorting rules; only object lists, ID lists, or deformgroups */ - if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) || (tselem->type == 0 && te->idcode == ID_OB)) { - int totelem = BLI_listbase_count(lb); - - if (totelem > 1) { - tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array"); - tTreeSort *tp = tear; - int skip = 0; - - for (te = lb->first; te; te = te->next, tp++) { - tselem = TREESTORE(te); - tp->te = te; - tp->name = te->name; - tp->idcode = te->idcode; - - if (tselem->type && tselem->type != TSE_DEFGROUP) { - tp->idcode = 0; // don't sort this - } - if (tselem->type == TSE_ID_BASE) { - tp->idcode = 1; // do sort this - } - - tp->id = tselem->id; - } - - /* just sort alphabetically */ - if (tear->idcode == 1) { - qsort(tear, totelem, sizeof(tTreeSort), treesort_alpha); - } - else { - /* keep beginning of list */ - for (tp = tear, skip = 0; skip < totelem; skip++, tp++) { - if (tp->idcode) { - break; - } - } - - if (skip < totelem) { - qsort(tear + skip, totelem - skip, sizeof(tTreeSort), treesort_alpha_ob); - } - } - - BLI_listbase_clear(lb); - tp = tear; - while (totelem--) { - BLI_addtail(lb, tp->te); - tp++; - } - MEM_freeN(tear); - } - } - - for (te = lb->first; te; te = te->next) { - outliner_sort(&te->subtree); - } + TreeElement *te; + TreeStoreElem *tselem; + + te = lb->last; + if (te == NULL) { + return; + } + tselem = TREESTORE(te); + + /* sorting rules; only object lists, ID lists, or deformgroups */ + if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) || + (tselem->type == 0 && te->idcode == ID_OB)) { + int totelem = BLI_listbase_count(lb); + + if (totelem > 1) { + tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array"); + tTreeSort *tp = tear; + int skip = 0; + + for (te = lb->first; te; te = te->next, tp++) { + tselem = TREESTORE(te); + tp->te = te; + tp->name = te->name; + tp->idcode = te->idcode; + + if (tselem->type && tselem->type != TSE_DEFGROUP) { + tp->idcode = 0; // don't sort this + } + if (tselem->type == TSE_ID_BASE) { + tp->idcode = 1; // do sort this + } + + tp->id = tselem->id; + } + + /* just sort alphabetically */ + if (tear->idcode == 1) { + qsort(tear, totelem, sizeof(tTreeSort), treesort_alpha); + } + else { + /* keep beginning of list */ + for (tp = tear, skip = 0; skip < totelem; skip++, tp++) { + if (tp->idcode) { + break; + } + } + + if (skip < totelem) { + qsort(tear + skip, totelem - skip, sizeof(tTreeSort), treesort_alpha_ob); + } + } + + BLI_listbase_clear(lb); + tp = tear; + while (totelem--) { + BLI_addtail(lb, tp->te); + tp++; + } + MEM_freeN(tear); + } + } + + for (te = lb->first; te; te = te->next) { + outliner_sort(&te->subtree); + } } /* Filtering ----------------------------------------------- */ typedef struct OutlinerTreeElementFocus { - TreeStoreElem *tselem; - int ys; + TreeStoreElem *tselem; + int ys; } OutlinerTreeElementFocus; /** * Bring the outliner scrolling back to where it was in relation to the original focus element * Caller is expected to handle redrawing of ARegion. */ -static void outliner_restore_scrolling_position(SpaceOutliner *soops, ARegion *ar, OutlinerTreeElementFocus *focus) +static void outliner_restore_scrolling_position(SpaceOutliner *soops, + ARegion *ar, + OutlinerTreeElementFocus *focus) { - View2D *v2d = &ar->v2d; - int ytop; + View2D *v2d = &ar->v2d; + int ytop; - if (focus->tselem != NULL) { - outliner_set_coordinates(ar, soops); + if (focus->tselem != NULL) { + outliner_set_coordinates(ar, soops); - TreeElement *te_new = outliner_find_tree_element(&soops->tree, focus->tselem); + TreeElement *te_new = outliner_find_tree_element(&soops->tree, focus->tselem); - if (te_new != NULL) { - int ys_new, ys_old; + if (te_new != NULL) { + int ys_new, ys_old; - ys_new = te_new->ys; - ys_old = focus->ys; + ys_new = te_new->ys; + ys_old = focus->ys; - ytop = v2d->cur.ymax + (ys_new - ys_old) -1; - if (ytop > 0) { - ytop = 0; - } + ytop = v2d->cur.ymax + (ys_new - ys_old) - 1; + if (ytop > 0) { + ytop = 0; + } - v2d->cur.ymax = (float)ytop; - v2d->cur.ymin = (float)(ytop - BLI_rcti_size_y(&v2d->mask)); - } - else { - return; - } - } + v2d->cur.ymax = (float)ytop; + v2d->cur.ymin = (float)(ytop - BLI_rcti_size_y(&v2d->mask)); + } + else { + return; + } + } } static bool test_collection_callback(TreeElement *te) { - return outliner_is_collection_tree_element(te); + return outliner_is_collection_tree_element(te); } static bool test_object_callback(TreeElement *te) { - TreeStoreElem *tselem = TREESTORE(te); - return ((tselem->type == 0) && (te->idcode == ID_OB)); + TreeStoreElem *tselem = TREESTORE(te); + return ((tselem->type == 0) && (te->idcode == ID_OB)); } /** * See if TreeElement or any of its children pass the callback_test. */ static TreeElement *outliner_find_first_desired_element_at_y_recursive( - const SpaceOutliner *soops, - TreeElement *te, - const float limit, - bool (*callback_test)(TreeElement *)) + const SpaceOutliner *soops, + TreeElement *te, + const float limit, + bool (*callback_test)(TreeElement *)) { - if (callback_test(te)) { - return te; - } - - if (TSELEM_OPEN(te->store_elem, soops)) { - TreeElement *te_iter, *te_sub; - for (te_iter = te->subtree.first; te_iter; te_iter = te_iter->next) { - te_sub = outliner_find_first_desired_element_at_y_recursive(soops, te_iter, limit, callback_test); - if (te_sub != NULL) { - return te_sub; - } - } - } - - return NULL; + if (callback_test(te)) { + return te; + } + + if (TSELEM_OPEN(te->store_elem, soops)) { + TreeElement *te_iter, *te_sub; + for (te_iter = te->subtree.first; te_iter; te_iter = te_iter->next) { + te_sub = outliner_find_first_desired_element_at_y_recursive( + soops, te_iter, limit, callback_test); + if (te_sub != NULL) { + return te_sub; + } + } + } + + return NULL; } /** @@ -1713,55 +1724,53 @@ static TreeElement *outliner_find_first_desired_element_at_y_recursive( * what we are looking for. If we are past the visible range and we can't find a valid element * we return NULL. */ -static TreeElement *outliner_find_first_desired_element_at_y( - const SpaceOutliner *soops, - const float view_co, - const float view_co_limit) +static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner *soops, + const float view_co, + const float view_co_limit) { - TreeElement *te, *te_sub; - te = outliner_find_item_at_y(soops, &soops->tree, view_co); - - bool (*callback_test)(TreeElement *); - if ((soops->outlinevis == SO_VIEW_LAYER) && - (soops->filter & SO_FILTER_NO_COLLECTION)) - { - callback_test = test_object_callback; - } - else { - callback_test = test_collection_callback; - } - - while (te != NULL) { - te_sub = outliner_find_first_desired_element_at_y_recursive(soops, te, view_co_limit, callback_test); - if (te_sub != NULL) { - /* Skip the element if it was not visible to start with. */ - if (te->ys + UI_UNIT_Y > view_co_limit) { - return te_sub; - } - else { - return NULL; - } - } - - if (te->next) { - te = te->next; - continue; - } - - if (te->parent == NULL) { - break; - } - - while (te->parent) { - if (te->parent->next) { - te = te->parent->next; - break; - } - te = te->parent; - } - } - - return NULL; + TreeElement *te, *te_sub; + te = outliner_find_item_at_y(soops, &soops->tree, view_co); + + bool (*callback_test)(TreeElement *); + if ((soops->outlinevis == SO_VIEW_LAYER) && (soops->filter & SO_FILTER_NO_COLLECTION)) { + callback_test = test_object_callback; + } + else { + callback_test = test_collection_callback; + } + + while (te != NULL) { + te_sub = outliner_find_first_desired_element_at_y_recursive( + soops, te, view_co_limit, callback_test); + if (te_sub != NULL) { + /* Skip the element if it was not visible to start with. */ + if (te->ys + UI_UNIT_Y > view_co_limit) { + return te_sub; + } + else { + return NULL; + } + } + + if (te->next) { + te = te->next; + continue; + } + + if (te->parent == NULL) { + break; + } + + while (te->parent) { + if (te->parent->next) { + te = te->parent->next; + break; + } + te = te->parent; + } + } + + return NULL; } /** @@ -1770,240 +1779,244 @@ static TreeElement *outliner_find_first_desired_element_at_y( * Finds the top-most collection visible in the outliner and populates the OutlinerTreeElementFocus * struct to retrieve this element later to make sure it is in the same original position as before filtering */ -static void outliner_store_scrolling_position(SpaceOutliner *soops, ARegion *ar, OutlinerTreeElementFocus *focus) +static void outliner_store_scrolling_position(SpaceOutliner *soops, + ARegion *ar, + OutlinerTreeElementFocus *focus) { - TreeElement *te; - float limit = ar->v2d.cur.ymin; + TreeElement *te; + float limit = ar->v2d.cur.ymin; - outliner_set_coordinates(ar, soops); + outliner_set_coordinates(ar, soops); - te = outliner_find_first_desired_element_at_y(soops, ar->v2d.cur.ymax, limit); + te = outliner_find_first_desired_element_at_y(soops, ar->v2d.cur.ymax, limit); - if (te != NULL) { - focus->tselem = TREESTORE(te); - focus->ys = te->ys; - } - else { - focus->tselem = NULL; - } + if (te != NULL) { + focus->tselem = TREESTORE(te); + focus->ys = te->ys; + } + else { + focus->tselem = NULL; + } } static int outliner_exclude_filter_get(SpaceOutliner *soops) { - int exclude_filter = soops->filter & ~SO_FILTER_OB_STATE; - - if (soops->search_string[0] != 0) { - exclude_filter |= SO_FILTER_SEARCH; - } - else { - exclude_filter &= ~SO_FILTER_SEARCH; - } - - /* Let's have this for the collection options at first. */ - if (!SUPPORT_FILTER_OUTLINER(soops)) { - return (exclude_filter & SO_FILTER_SEARCH); - } - - if (soops->filter & SO_FILTER_NO_OBJECT) { - exclude_filter |= SO_FILTER_OB_TYPE; - } - - switch (soops->filter_state) { - case SO_FILTER_OB_VISIBLE: - exclude_filter |= SO_FILTER_OB_STATE_VISIBLE; - break; - case SO_FILTER_OB_SELECTED: - exclude_filter |= SO_FILTER_OB_STATE_SELECTED; - break; - case SO_FILTER_OB_ACTIVE: - exclude_filter |= SO_FILTER_OB_STATE_ACTIVE; - break; - } - - return exclude_filter; + int exclude_filter = soops->filter & ~SO_FILTER_OB_STATE; + + if (soops->search_string[0] != 0) { + exclude_filter |= SO_FILTER_SEARCH; + } + else { + exclude_filter &= ~SO_FILTER_SEARCH; + } + + /* Let's have this for the collection options at first. */ + if (!SUPPORT_FILTER_OUTLINER(soops)) { + return (exclude_filter & SO_FILTER_SEARCH); + } + + if (soops->filter & SO_FILTER_NO_OBJECT) { + exclude_filter |= SO_FILTER_OB_TYPE; + } + + switch (soops->filter_state) { + case SO_FILTER_OB_VISIBLE: + exclude_filter |= SO_FILTER_OB_STATE_VISIBLE; + break; + case SO_FILTER_OB_SELECTED: + exclude_filter |= SO_FILTER_OB_STATE_SELECTED; + break; + case SO_FILTER_OB_ACTIVE: + exclude_filter |= SO_FILTER_OB_STATE_ACTIVE; + break; + } + + return exclude_filter; } -static bool outliner_element_visible_get(ViewLayer *view_layer, TreeElement *te, const int exclude_filter) +static bool outliner_element_visible_get(ViewLayer *view_layer, + TreeElement *te, + const int exclude_filter) { - if ((exclude_filter & SO_FILTER_ANY) == 0) { - return true; - } - - TreeStoreElem *tselem = TREESTORE(te); - if ((tselem->type == 0) && (te->idcode == ID_OB)) { - if ((exclude_filter & SO_FILTER_OB_TYPE) == SO_FILTER_OB_TYPE) { - return false; - } - - Object *ob = (Object *)tselem->id; - Base *base = (Base *)te->directdata; - BLI_assert((base == NULL) || (base->object == ob)); - - if (exclude_filter & SO_FILTER_OB_TYPE) { - switch (ob->type) { - case OB_MESH: - if (exclude_filter & SO_FILTER_NO_OB_MESH) { - return false; - } - break; - case OB_ARMATURE: - if (exclude_filter & SO_FILTER_NO_OB_ARMATURE) { - return false; - } - break; - case OB_EMPTY: - if (exclude_filter & SO_FILTER_NO_OB_EMPTY) { - return false; - } - break; - case OB_LAMP: - if (exclude_filter & SO_FILTER_NO_OB_LAMP) { - return false; - } - break; - case OB_CAMERA: - if (exclude_filter & SO_FILTER_NO_OB_CAMERA) { - return false; - } - break; - default: - if (exclude_filter & SO_FILTER_NO_OB_OTHERS) { - return false; - } - break; - } - } - - if (exclude_filter & SO_FILTER_OB_STATE) { - if (base == NULL) { - base = BKE_view_layer_base_find(view_layer, ob); - - if (base == NULL) { - return false; - } - } - - if (exclude_filter & SO_FILTER_OB_STATE_VISIBLE) { - if ((base->flag & BASE_VISIBLE) == 0) { - return false; - } - } - else if (exclude_filter & SO_FILTER_OB_STATE_SELECTED) { - if ((base->flag & BASE_SELECTED) == 0) { - return false; - } - } - else { - BLI_assert(exclude_filter & SO_FILTER_OB_STATE_ACTIVE); - if (base != BASACT(view_layer)) { - return false; - } - } - } - - if ((te->parent != NULL) && - (TREESTORE(te->parent)->type == 0) && (te->parent->idcode == ID_OB)) - { - if (exclude_filter & SO_FILTER_NO_CHILDREN) { - return false; - } - } - } - else if (te->parent != NULL && - TREESTORE(te->parent)->type == 0 && te->parent->idcode == ID_OB) - { - if (exclude_filter & SO_FILTER_NO_OB_CONTENT) { - return false; - } - } - - return true; + if ((exclude_filter & SO_FILTER_ANY) == 0) { + return true; + } + + TreeStoreElem *tselem = TREESTORE(te); + if ((tselem->type == 0) && (te->idcode == ID_OB)) { + if ((exclude_filter & SO_FILTER_OB_TYPE) == SO_FILTER_OB_TYPE) { + return false; + } + + Object *ob = (Object *)tselem->id; + Base *base = (Base *)te->directdata; + BLI_assert((base == NULL) || (base->object == ob)); + + if (exclude_filter & SO_FILTER_OB_TYPE) { + switch (ob->type) { + case OB_MESH: + if (exclude_filter & SO_FILTER_NO_OB_MESH) { + return false; + } + break; + case OB_ARMATURE: + if (exclude_filter & SO_FILTER_NO_OB_ARMATURE) { + return false; + } + break; + case OB_EMPTY: + if (exclude_filter & SO_FILTER_NO_OB_EMPTY) { + return false; + } + break; + case OB_LAMP: + if (exclude_filter & SO_FILTER_NO_OB_LAMP) { + return false; + } + break; + case OB_CAMERA: + if (exclude_filter & SO_FILTER_NO_OB_CAMERA) { + return false; + } + break; + default: + if (exclude_filter & SO_FILTER_NO_OB_OTHERS) { + return false; + } + break; + } + } + + if (exclude_filter & SO_FILTER_OB_STATE) { + if (base == NULL) { + base = BKE_view_layer_base_find(view_layer, ob); + + if (base == NULL) { + return false; + } + } + + if (exclude_filter & SO_FILTER_OB_STATE_VISIBLE) { + if ((base->flag & BASE_VISIBLE) == 0) { + return false; + } + } + else if (exclude_filter & SO_FILTER_OB_STATE_SELECTED) { + if ((base->flag & BASE_SELECTED) == 0) { + return false; + } + } + else { + BLI_assert(exclude_filter & SO_FILTER_OB_STATE_ACTIVE); + if (base != BASACT(view_layer)) { + return false; + } + } + } + + if ((te->parent != NULL) && (TREESTORE(te->parent)->type == 0) && + (te->parent->idcode == ID_OB)) { + if (exclude_filter & SO_FILTER_NO_CHILDREN) { + return false; + } + } + } + else if (te->parent != NULL && TREESTORE(te->parent)->type == 0 && te->parent->idcode == ID_OB) { + if (exclude_filter & SO_FILTER_NO_OB_CONTENT) { + return false; + } + } + + return true; } static bool outliner_filter_has_name(TreeElement *te, const char *name, int flags) { - int fn_flag = 0; + int fn_flag = 0; - if ((flags & SO_FIND_CASE_SENSITIVE) == 0) { - fn_flag |= FNM_CASEFOLD; - } + if ((flags & SO_FIND_CASE_SENSITIVE) == 0) { + fn_flag |= FNM_CASEFOLD; + } - return fnmatch(name, te->name, fn_flag) == 0; + return fnmatch(name, te->name, fn_flag) == 0; } -static int outliner_filter_subtree( - SpaceOutliner *soops, ViewLayer *view_layer, ListBase *lb, const char *search_string, const int exclude_filter) +static int outliner_filter_subtree(SpaceOutliner *soops, + ViewLayer *view_layer, + ListBase *lb, + const char *search_string, + const int exclude_filter) { - TreeElement *te, *te_next; - TreeStoreElem *tselem; - - for (te = lb->first; te; te = te_next) { - te_next = te->next; - - if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) { - outliner_free_tree_element(te, lb); - continue; - } - else if ((exclude_filter & SO_FILTER_SEARCH) == 0) { - /* Filter subtree too. */ - outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter); - continue; - } - - if (!outliner_filter_has_name(te, search_string, soops->search_flags)) { - /* item isn't something we're looking for, but... - * - if the subtree is expanded, check if there are any matches that can be easily found - * so that searching for "cu" in the default scene will still match the Cube - * - otherwise, we can't see within the subtree and the item doesn't match, - * so these can be safely ignored (i.e. the subtree can get freed) - */ - tselem = TREESTORE(te); - - /* flag as not a found item */ - tselem->flag &= ~TSE_SEARCHMATCH; - - if ((!TSELEM_OPEN(tselem, soops)) || - outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter) == 0) - { - outliner_free_tree_element(te, lb); - } - } - else { - tselem = TREESTORE(te); - - /* flag as a found item - we can then highlight it */ - tselem->flag |= TSE_SEARCHMATCH; - - /* filter subtree too */ - outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter); - } - } - - /* if there are still items in the list, that means that there were still some matches */ - return (BLI_listbase_is_empty(lb) == false); + TreeElement *te, *te_next; + TreeStoreElem *tselem; + + for (te = lb->first; te; te = te_next) { + te_next = te->next; + + if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) { + outliner_free_tree_element(te, lb); + continue; + } + else if ((exclude_filter & SO_FILTER_SEARCH) == 0) { + /* Filter subtree too. */ + outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter); + continue; + } + + if (!outliner_filter_has_name(te, search_string, soops->search_flags)) { + /* item isn't something we're looking for, but... + * - if the subtree is expanded, check if there are any matches that can be easily found + * so that searching for "cu" in the default scene will still match the Cube + * - otherwise, we can't see within the subtree and the item doesn't match, + * so these can be safely ignored (i.e. the subtree can get freed) + */ + tselem = TREESTORE(te); + + /* flag as not a found item */ + tselem->flag &= ~TSE_SEARCHMATCH; + + if ((!TSELEM_OPEN(tselem, soops)) || + outliner_filter_subtree( + soops, view_layer, &te->subtree, search_string, exclude_filter) == 0) { + outliner_free_tree_element(te, lb); + } + } + else { + tselem = TREESTORE(te); + + /* flag as a found item - we can then highlight it */ + tselem->flag |= TSE_SEARCHMATCH; + + /* filter subtree too */ + outliner_filter_subtree(soops, view_layer, &te->subtree, search_string, exclude_filter); + } + } + + /* if there are still items in the list, that means that there were still some matches */ + return (BLI_listbase_is_empty(lb) == false); } static void outliner_filter_tree(SpaceOutliner *soops, ViewLayer *view_layer) { - char search_buff[sizeof(((struct SpaceOutliner *)NULL)->search_string) + 2]; - char *search_string; + char search_buff[sizeof(((struct SpaceOutliner *)NULL)->search_string) + 2]; + char *search_string; - const int exclude_filter = outliner_exclude_filter_get(soops); + const int exclude_filter = outliner_exclude_filter_get(soops); - if (exclude_filter == 0) { - return; - } + if (exclude_filter == 0) { + return; + } - if (soops->search_flags & SO_FIND_COMPLETE) { - search_string = soops->search_string; - } - else { - /* Implicitly add heading/trailing wildcards if needed. */ - BLI_strncpy_ensure_pad(search_buff, soops->search_string, '*', sizeof(search_buff)); - search_string = search_buff; - } + if (soops->search_flags & SO_FIND_COMPLETE) { + search_string = soops->search_string; + } + else { + /* Implicitly add heading/trailing wildcards if needed. */ + BLI_strncpy_ensure_pad(search_buff, soops->search_string, '*', sizeof(search_buff)); + search_string = search_buff; + } - outliner_filter_subtree(soops, view_layer, &soops->tree, search_string, exclude_filter); + outliner_filter_subtree(soops, view_layer, &soops->tree, search_string, exclude_filter); } /* ======================================================= */ @@ -2011,172 +2024,173 @@ static void outliner_filter_tree(SpaceOutliner *soops, ViewLayer *view_layer) /* Main entry point for building the tree data-structure that the outliner represents */ // TODO: split each mode into its own function? -void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, SpaceOutliner *soops, ARegion *ar) +void outliner_build_tree( + Main *mainvar, Scene *scene, ViewLayer *view_layer, SpaceOutliner *soops, ARegion *ar) { - TreeElement *te = NULL, *ten; - TreeStoreElem *tselem; - /* on first view, we open scenes */ - int show_opened = !soops->treestore || !BLI_mempool_len(soops->treestore); - - /* Are we looking for something - we want to tag parents to filter child matches - * - NOT in datablocks view - searching all datablocks takes way too long to be useful - * - this variable is only set once per tree build */ - if (soops->search_string[0] != 0 && soops->outlinevis != SO_DATA_API) { - soops->search_flags |= SO_SEARCH_RECURSIVE; - } - else { - soops->search_flags &= ~SO_SEARCH_RECURSIVE; - } - - if (soops->treehash && (soops->storeflag & SO_TREESTORE_REBUILD) && soops->treestore) { - soops->storeflag &= ~SO_TREESTORE_REBUILD; - BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore); - } - - if (ar->do_draw & RGN_DRAW_NO_REBUILD) { - return; - } - - OutlinerTreeElementFocus focus; - outliner_store_scrolling_position(soops, ar, &focus); - - outliner_free_tree(&soops->tree); - outliner_storage_cleanup(soops); - - /* options */ - if (soops->outlinevis == SO_LIBRARIES) { - Library *lib; - - /* current file first - mainvar provides tselem with unique pointer - not used */ - ten = outliner_add_library_contents(mainvar, soops, &soops->tree, NULL); - if (ten) { - tselem = TREESTORE(ten); - if (!tselem->used) { - tselem->flag &= ~TSE_CLOSED; - } - } - - for (lib = mainvar->libraries.first; lib; lib = lib->id.next) { - ten = outliner_add_library_contents(mainvar, soops, &soops->tree, lib); - if (ten) { - lib->id.newid = (ID *)ten; - } - - } - /* make hierarchy */ - ten = soops->tree.first; - if (ten != NULL) { - ten = ten->next; /* first one is main */ - while (ten) { - TreeElement *nten = ten->next, *par; - tselem = TREESTORE(ten); - lib = (Library *)tselem->id; - if (lib && lib->parent) { - par = (TreeElement *)lib->parent->id.newid; - if (tselem->id->tag & LIB_TAG_INDIRECT) { - /* Only remove from 'first level' if lib is not also directly used. */ - BLI_remlink(&soops->tree, ten); - BLI_addtail(&par->subtree, ten); - ten->parent = par; - } - else { - /* Else, make a new copy of the libtree for our parent. */ - TreeElement *dupten = outliner_add_library_contents(mainvar, soops, &par->subtree, lib); - if (dupten) { - dupten->parent = par; - } - } - } - ten = nten; - } - } - /* restore newid pointers */ - for (lib = mainvar->libraries.first; lib; lib = lib->id.next) { - lib->id.newid = NULL; - } - - } - else if (soops->outlinevis == SO_SCENES) { - Scene *sce; - for (sce = mainvar->scenes.first; sce; sce = sce->id.next) { - te = outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0); - tselem = TREESTORE(te); - - if (sce == scene && show_opened) { - tselem->flag &= ~TSE_CLOSED; - } - - outliner_make_object_parent_hierarchy(&te->subtree); - } - } - else if (soops->outlinevis == SO_SEQUENCE) { - Sequence *seq; - Editing *ed = BKE_sequencer_editing_get(scene, false); - int op; - - if (ed == NULL) { - return; - } - - seq = ed->seqbasep->first; - if (!seq) { - return; - } - - while (seq) { - op = need_add_seq_dup(seq); - if (op == 1) { - /* ten = */ outliner_add_element(soops, &soops->tree, (void *)seq, NULL, TSE_SEQUENCE, 0); - } - else if (op == 0) { - ten = outliner_add_element(soops, &soops->tree, (void *)seq, NULL, TSE_SEQUENCE_DUP, 0); - outliner_add_seq_dup(soops, seq, ten, 0); - } - seq = seq->next; - } - } - else if (soops->outlinevis == SO_DATA_API) { - PointerRNA mainptr; - - RNA_main_pointer_create(mainvar, &mainptr); - - ten = outliner_add_element(soops, &soops->tree, (void *)&mainptr, NULL, TSE_RNA_STRUCT, -1); - - if (show_opened) { - tselem = TREESTORE(ten); - tselem->flag &= ~TSE_CLOSED; - } - } - else if (soops->outlinevis == SO_ID_ORPHANS) { - outliner_add_orphaned_datablocks(mainvar, soops); - } - else if (soops->outlinevis == SO_VIEW_LAYER) { - if (soops->filter & SO_FILTER_NO_COLLECTION) { - /* Show objects in the view layer. */ - for (Base *base = view_layer->object_bases.first; base; base = base->next) { - TreeElement *te_object = outliner_add_element(soops, &soops->tree, base->object, NULL, 0, 0); - te_object->directdata = base; - } - - outliner_make_object_parent_hierarchy(&soops->tree); - } - else { - /* Show collections in the view layer. */ - ten = outliner_add_element(soops, &soops->tree, scene, NULL, TSE_VIEW_COLLECTION_BASE, 0); - ten->name = IFACE_("Scene Collection"); - TREESTORE(ten)->flag &= ~TSE_CLOSED; - - bool show_objects = !(soops->filter & SO_FILTER_NO_OBJECT); - outliner_add_view_layer(soops, &ten->subtree, ten, view_layer, show_objects); - } - } - - if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) { - outliner_sort(&soops->tree); - } - - outliner_filter_tree(soops, view_layer); - outliner_restore_scrolling_position(soops, ar, &focus); - - BKE_main_id_clear_newpoins(mainvar); + TreeElement *te = NULL, *ten; + TreeStoreElem *tselem; + /* on first view, we open scenes */ + int show_opened = !soops->treestore || !BLI_mempool_len(soops->treestore); + + /* Are we looking for something - we want to tag parents to filter child matches + * - NOT in datablocks view - searching all datablocks takes way too long to be useful + * - this variable is only set once per tree build */ + if (soops->search_string[0] != 0 && soops->outlinevis != SO_DATA_API) { + soops->search_flags |= SO_SEARCH_RECURSIVE; + } + else { + soops->search_flags &= ~SO_SEARCH_RECURSIVE; + } + + if (soops->treehash && (soops->storeflag & SO_TREESTORE_REBUILD) && soops->treestore) { + soops->storeflag &= ~SO_TREESTORE_REBUILD; + BKE_outliner_treehash_rebuild_from_treestore(soops->treehash, soops->treestore); + } + + if (ar->do_draw & RGN_DRAW_NO_REBUILD) { + return; + } + + OutlinerTreeElementFocus focus; + outliner_store_scrolling_position(soops, ar, &focus); + + outliner_free_tree(&soops->tree); + outliner_storage_cleanup(soops); + + /* options */ + if (soops->outlinevis == SO_LIBRARIES) { + Library *lib; + + /* current file first - mainvar provides tselem with unique pointer - not used */ + ten = outliner_add_library_contents(mainvar, soops, &soops->tree, NULL); + if (ten) { + tselem = TREESTORE(ten); + if (!tselem->used) { + tselem->flag &= ~TSE_CLOSED; + } + } + + for (lib = mainvar->libraries.first; lib; lib = lib->id.next) { + ten = outliner_add_library_contents(mainvar, soops, &soops->tree, lib); + if (ten) { + lib->id.newid = (ID *)ten; + } + } + /* make hierarchy */ + ten = soops->tree.first; + if (ten != NULL) { + ten = ten->next; /* first one is main */ + while (ten) { + TreeElement *nten = ten->next, *par; + tselem = TREESTORE(ten); + lib = (Library *)tselem->id; + if (lib && lib->parent) { + par = (TreeElement *)lib->parent->id.newid; + if (tselem->id->tag & LIB_TAG_INDIRECT) { + /* Only remove from 'first level' if lib is not also directly used. */ + BLI_remlink(&soops->tree, ten); + BLI_addtail(&par->subtree, ten); + ten->parent = par; + } + else { + /* Else, make a new copy of the libtree for our parent. */ + TreeElement *dupten = outliner_add_library_contents( + mainvar, soops, &par->subtree, lib); + if (dupten) { + dupten->parent = par; + } + } + } + ten = nten; + } + } + /* restore newid pointers */ + for (lib = mainvar->libraries.first; lib; lib = lib->id.next) { + lib->id.newid = NULL; + } + } + else if (soops->outlinevis == SO_SCENES) { + Scene *sce; + for (sce = mainvar->scenes.first; sce; sce = sce->id.next) { + te = outliner_add_element(soops, &soops->tree, sce, NULL, 0, 0); + tselem = TREESTORE(te); + + if (sce == scene && show_opened) { + tselem->flag &= ~TSE_CLOSED; + } + + outliner_make_object_parent_hierarchy(&te->subtree); + } + } + else if (soops->outlinevis == SO_SEQUENCE) { + Sequence *seq; + Editing *ed = BKE_sequencer_editing_get(scene, false); + int op; + + if (ed == NULL) { + return; + } + + seq = ed->seqbasep->first; + if (!seq) { + return; + } + + while (seq) { + op = need_add_seq_dup(seq); + if (op == 1) { + /* ten = */ outliner_add_element(soops, &soops->tree, (void *)seq, NULL, TSE_SEQUENCE, 0); + } + else if (op == 0) { + ten = outliner_add_element(soops, &soops->tree, (void *)seq, NULL, TSE_SEQUENCE_DUP, 0); + outliner_add_seq_dup(soops, seq, ten, 0); + } + seq = seq->next; + } + } + else if (soops->outlinevis == SO_DATA_API) { + PointerRNA mainptr; + + RNA_main_pointer_create(mainvar, &mainptr); + + ten = outliner_add_element(soops, &soops->tree, (void *)&mainptr, NULL, TSE_RNA_STRUCT, -1); + + if (show_opened) { + tselem = TREESTORE(ten); + tselem->flag &= ~TSE_CLOSED; + } + } + else if (soops->outlinevis == SO_ID_ORPHANS) { + outliner_add_orphaned_datablocks(mainvar, soops); + } + else if (soops->outlinevis == SO_VIEW_LAYER) { + if (soops->filter & SO_FILTER_NO_COLLECTION) { + /* Show objects in the view layer. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + TreeElement *te_object = outliner_add_element( + soops, &soops->tree, base->object, NULL, 0, 0); + te_object->directdata = base; + } + + outliner_make_object_parent_hierarchy(&soops->tree); + } + else { + /* Show collections in the view layer. */ + ten = outliner_add_element(soops, &soops->tree, scene, NULL, TSE_VIEW_COLLECTION_BASE, 0); + ten->name = IFACE_("Scene Collection"); + TREESTORE(ten)->flag &= ~TSE_CLOSED; + + bool show_objects = !(soops->filter & SO_FILTER_NO_OBJECT); + outliner_add_view_layer(soops, &ten->subtree, ten, view_layer, show_objects); + } + } + + if ((soops->flag & SO_SKIP_SORT_ALPHA) == 0) { + outliner_sort(&soops->tree); + } + + outliner_filter_tree(soops, view_layer); + outliner_restore_scrolling_position(soops, ar, &focus); + + BKE_main_id_clear_newpoins(mainvar); } diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c index a44a6e605de..03d15088380 100644 --- a/source/blender/editors/space_outliner/outliner_utils.c +++ b/source/blender/editors/space_outliner/outliner_utils.c @@ -38,25 +38,27 @@ * Try to find an item under y-coordinate \a view_co_y (view-space). * \note Recursive */ -TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops, const ListBase *tree, float view_co_y) +TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops, + const ListBase *tree, + float view_co_y) { - for (TreeElement *te_iter = tree->first; te_iter; te_iter = te_iter->next) { - if (view_co_y < (te_iter->ys + UI_UNIT_Y)) { - if (view_co_y >= te_iter->ys) { - /* co_y is inside this element */ - return te_iter; - } - else if (TSELEM_OPEN(te_iter->store_elem, soops)) { - /* co_y is lower than current element, possibly inside children */ - TreeElement *te_sub = outliner_find_item_at_y(soops, &te_iter->subtree, view_co_y); - if (te_sub) { - return te_sub; - } - } - } - } - - return NULL; + for (TreeElement *te_iter = tree->first; te_iter; te_iter = te_iter->next) { + if (view_co_y < (te_iter->ys + UI_UNIT_Y)) { + if (view_co_y >= te_iter->ys) { + /* co_y is inside this element */ + return te_iter; + } + else if (TSELEM_OPEN(te_iter->store_elem, soops)) { + /* co_y is lower than current element, possibly inside children */ + TreeElement *te_sub = outliner_find_item_at_y(soops, &te_iter->subtree, view_co_y); + if (te_sub) { + return te_sub; + } + } + } + } + + return NULL; } /** @@ -65,146 +67,150 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops, const ListBase * * \return a hovered child item or \a parent_te (if no hovered child found). */ -TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *soops, const TreeElement *parent_te, float view_co_x) +TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *soops, + const TreeElement *parent_te, + float view_co_x) { - /* if parent_te is opened, it doesn't show childs in row */ - if (!TSELEM_OPEN(TREESTORE(parent_te), soops)) { - /* no recursion, items can only display their direct children in the row */ - for (TreeElement *child_te = parent_te->subtree.first; - /* don't look further if co_x is smaller than child position*/ - child_te && view_co_x >= child_te->xs; - - child_te = child_te->next) - { - if ((child_te->flag & TE_ICONROW) && (view_co_x > child_te->xs) && (view_co_x < child_te->xend)) { - return child_te; - } - } - } - - /* return parent if no child is hovered */ - return (TreeElement *)parent_te; + /* if parent_te is opened, it doesn't show childs in row */ + if (!TSELEM_OPEN(TREESTORE(parent_te), soops)) { + /* no recursion, items can only display their direct children in the row */ + for (TreeElement *child_te = parent_te->subtree.first; + /* don't look further if co_x is smaller than child position*/ + child_te && view_co_x >= child_te->xs; + + child_te = child_te->next) { + if ((child_te->flag & TE_ICONROW) && (view_co_x > child_te->xs) && + (view_co_x < child_te->xend)) { + return child_te; + } + } + } + + /* return parent if no child is hovered */ + return (TreeElement *)parent_te; } /* Find specific item from the treestore */ TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store_elem) { - TreeElement *te, *tes; - for (te = lb->first; te; te = te->next) { - if (te->store_elem == store_elem) { - return te; - } - tes = outliner_find_tree_element(&te->subtree, store_elem); - if (tes) { - return tes; - } - } - return NULL; + TreeElement *te, *tes; + for (te = lb->first; te; te = te->next) { + if (te->store_elem == store_elem) { + return te; + } + tes = outliner_find_tree_element(&te->subtree, store_elem); + if (tes) { + return tes; + } + } + return NULL; } /* Find parent element of te */ -TreeElement *outliner_find_parent_element(ListBase *lb, TreeElement *parent_te, const TreeElement *child_te) +TreeElement *outliner_find_parent_element(ListBase *lb, + TreeElement *parent_te, + const TreeElement *child_te) { - TreeElement *te; - for (te = lb->first; te; te = te->next) { - if (te == child_te) { - return parent_te; - } - - TreeElement *find_te = outliner_find_parent_element(&te->subtree, te, child_te); - if (find_te) { - return find_te; - } - } - return NULL; + TreeElement *te; + for (te = lb->first; te; te = te->next) { + if (te == child_te) { + return parent_te; + } + + TreeElement *find_te = outliner_find_parent_element(&te->subtree, te, child_te); + if (find_te) { + return find_te; + } + } + return NULL; } /* tse is not in the treestore, we use its contents to find a match */ TreeElement *outliner_find_tse(SpaceOutliner *soops, const TreeStoreElem *tse) { - TreeStoreElem *tselem; + TreeStoreElem *tselem; - if (tse->id == NULL) { - return NULL; - } + if (tse->id == NULL) { + return NULL; + } - /* check if 'tse' is in treestore */ - tselem = BKE_outliner_treehash_lookup_any(soops->treehash, tse->type, tse->nr, tse->id); - if (tselem) { - return outliner_find_tree_element(&soops->tree, tselem); - } + /* check if 'tse' is in treestore */ + tselem = BKE_outliner_treehash_lookup_any(soops->treehash, tse->type, tse->nr, tse->id); + if (tselem) { + return outliner_find_tree_element(&soops->tree, tselem); + } - return NULL; + return NULL; } /* Find treestore that refers to given ID */ TreeElement *outliner_find_id(SpaceOutliner *soops, ListBase *lb, const ID *id) { - for (TreeElement *te = lb->first; te; te = te->next) { - TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0) { - if (tselem->id == id) { - return te; - } - } - - TreeElement *tes = outliner_find_id(soops, &te->subtree, id); - if (tes) { - return tes; - } - } - return NULL; + for (TreeElement *te = lb->first; te; te = te->next) { + TreeStoreElem *tselem = TREESTORE(te); + if (tselem->type == 0) { + if (tselem->id == id) { + return te; + } + } + + TreeElement *tes = outliner_find_id(soops, &te->subtree, id); + if (tes) { + return tes; + } + } + return NULL; } TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan) { - for (TreeElement *te = lb->first; te; te = te->next) { - if (te->directdata == pchan) { - return te; - } - - TreeStoreElem *tselem = TREESTORE(te); - if (ELEM(tselem->type, TSE_POSE_BASE, TSE_POSE_CHANNEL)) { - TreeElement *tes = outliner_find_posechannel(&te->subtree, pchan); - if (tes) { - return tes; - } - } - } - return NULL; + for (TreeElement *te = lb->first; te; te = te->next) { + if (te->directdata == pchan) { + return te; + } + + TreeStoreElem *tselem = TREESTORE(te); + if (ELEM(tselem->type, TSE_POSE_BASE, TSE_POSE_CHANNEL)) { + TreeElement *tes = outliner_find_posechannel(&te->subtree, pchan); + if (tes) { + return tes; + } + } + } + return NULL; } TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone) { - for (TreeElement *te = lb->first; te; te = te->next) { - if (te->directdata == ebone) { - return te; - } - - TreeStoreElem *tselem = TREESTORE(te); - if (ELEM(tselem->type, 0, TSE_EBONE)) { - TreeElement *tes = outliner_find_editbone(&te->subtree, ebone); - if (tes) { - return tes; - } - } - } - return NULL; + for (TreeElement *te = lb->first; te; te = te->next) { + if (te->directdata == ebone) { + return te; + } + + TreeStoreElem *tselem = TREESTORE(te); + if (ELEM(tselem->type, 0, TSE_EBONE)) { + TreeElement *tes = outliner_find_editbone(&te->subtree, ebone); + if (tes) { + return tes; + } + } + } + return NULL; } ID *outliner_search_back(SpaceOutliner *UNUSED(soops), TreeElement *te, short idcode) { - TreeStoreElem *tselem; - te = te->parent; - - while (te) { - tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == idcode) { - return tselem->id; - } - te = te->parent; - } - return NULL; + TreeStoreElem *tselem; + te = te->parent; + + while (te) { + tselem = TREESTORE(te); + if (tselem->type == 0 && te->idcode == idcode) { + return tselem->id; + } + te = te->parent; + } + return NULL; } /** @@ -215,38 +221,43 @@ ID *outliner_search_back(SpaceOutliner *UNUSED(soops), TreeElement *te, short id * \param filter_tselem_flag: Same as \a filter_te_flag, but for the TreeStoreElem. * \param func: Custom callback to execute for each visited item. */ -bool outliner_tree_traverse(const SpaceOutliner *soops, ListBase *tree, int filter_te_flag, int filter_tselem_flag, - TreeTraversalFunc func, void *customdata) +bool outliner_tree_traverse(const SpaceOutliner *soops, + ListBase *tree, + int filter_te_flag, + int filter_tselem_flag, + TreeTraversalFunc func, + void *customdata) { - for (TreeElement *te = tree->first, *te_next; te; te = te_next) { - TreeTraversalAction func_retval = TRAVERSE_CONTINUE; - /* in case te is freed in callback */ - TreeStoreElem *tselem = TREESTORE(te); - ListBase subtree = te->subtree; - te_next = te->next; - - if (filter_te_flag && (te->flag & filter_te_flag) == 0) { - /* skip */ - } - else if (filter_tselem_flag && (tselem->flag & filter_tselem_flag) == 0) { - /* skip */ - } - else { - func_retval = func(te, customdata); - } - /* Don't access te or tselem from now on! Might've been freed... */ - - if (func_retval == TRAVERSE_BREAK) { - return false; - } - - if (func_retval == TRAVERSE_SKIP_CHILDS) { - /* skip */ - } - else if (!outliner_tree_traverse(soops, &subtree, filter_te_flag, filter_tselem_flag, func, customdata)) { - return false; - } - } - - return true; + for (TreeElement *te = tree->first, *te_next; te; te = te_next) { + TreeTraversalAction func_retval = TRAVERSE_CONTINUE; + /* in case te is freed in callback */ + TreeStoreElem *tselem = TREESTORE(te); + ListBase subtree = te->subtree; + te_next = te->next; + + if (filter_te_flag && (te->flag & filter_te_flag) == 0) { + /* skip */ + } + else if (filter_tselem_flag && (tselem->flag & filter_tselem_flag) == 0) { + /* skip */ + } + else { + func_retval = func(te, customdata); + } + /* Don't access te or tselem from now on! Might've been freed... */ + + if (func_retval == TRAVERSE_BREAK) { + return false; + } + + if (func_retval == TRAVERSE_SKIP_CHILDS) { + /* skip */ + } + else if (!outliner_tree_traverse( + soops, &subtree, filter_te_flag, filter_tselem_flag, func, customdata)) { + return false; + } + } + + return true; } diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index dc51d501b99..26b97a1cdd9 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -21,7 +21,6 @@ * \ingroup spoutliner */ - #include <string.h> #include <stdio.h> @@ -52,380 +51,381 @@ #include "UI_resources.h" #include "UI_view2d.h" - #include "outliner_intern.h" #include "GPU_framebuffer.h" static void outliner_main_region_init(wmWindowManager *wm, ARegion *ar) { - ListBase *lb; - wmKeyMap *keymap; - - /* make sure we keep the hide flags */ - ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); - ar->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP); /* prevent any noise of past */ - ar->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE; - ar->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE; - - ar->v2d.align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y); - ar->v2d.keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); - ar->v2d.keeptot = V2D_KEEPTOT_STRICT; - ar->v2d.minzoom = ar->v2d.maxzoom = 1.0f; - - UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); - - /* own keymap */ - keymap = WM_keymap_ensure(wm->defaultconf, "Outliner", SPACE_OUTLINER, 0); - /* don't pass on view2d mask, it's always set with scrollbar space, hide fails */ - WM_event_add_keymap_handler_bb(&ar->handlers, keymap, NULL, &ar->winrct); - - /* Add dropboxes */ - lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW); - WM_event_add_dropbox_handler(&ar->handlers, lb); + ListBase *lb; + wmKeyMap *keymap; + + /* make sure we keep the hide flags */ + ar->v2d.scroll |= (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); + ar->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP); /* prevent any noise of past */ + ar->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE; + ar->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE; + + ar->v2d.align = (V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y); + ar->v2d.keepzoom = (V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT); + ar->v2d.keeptot = V2D_KEEPTOT_STRICT; + ar->v2d.minzoom = ar->v2d.maxzoom = 1.0f; + + UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); + + /* own keymap */ + keymap = WM_keymap_ensure(wm->defaultconf, "Outliner", SPACE_OUTLINER, 0); + /* don't pass on view2d mask, it's always set with scrollbar space, hide fails */ + WM_event_add_keymap_handler_bb(&ar->handlers, keymap, NULL, &ar->winrct); + + /* Add dropboxes */ + lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW); + WM_event_add_dropbox_handler(&ar->handlers, lb); } static void outliner_main_region_draw(const bContext *C, ARegion *ar) { - View2D *v2d = &ar->v2d; - View2DScrollers *scrollers; + View2D *v2d = &ar->v2d; + View2DScrollers *scrollers; - /* clear */ - UI_ThemeClearColor(TH_BACK); - GPU_clear(GPU_COLOR_BIT); + /* clear */ + UI_ThemeClearColor(TH_BACK); + GPU_clear(GPU_COLOR_BIT); - draw_outliner(C); + draw_outliner(C); - /* reset view matrix */ - UI_view2d_view_restore(C); + /* reset view matrix */ + UI_view2d_view_restore(C); - /* scrollers */ - scrollers = UI_view2d_scrollers_calc(C, v2d, NULL, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY); - UI_view2d_scrollers_draw(C, v2d, scrollers); - UI_view2d_scrollers_free(scrollers); + /* scrollers */ + scrollers = UI_view2d_scrollers_calc( + C, v2d, NULL, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY); + UI_view2d_scrollers_draw(C, v2d, scrollers); + UI_view2d_scrollers_free(scrollers); } - static void outliner_main_region_free(ARegion *UNUSED(ar)) { - } -static void outliner_main_region_listener( - wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar, - wmNotifier *wmn, const Scene *UNUSED(scene)) +static void outliner_main_region_listener(wmWindow *UNUSED(win), + ScrArea *UNUSED(sa), + ARegion *ar, + wmNotifier *wmn, + const Scene *UNUSED(scene)) { - /* context changes */ - switch (wmn->category) { - case NC_SCENE: - switch (wmn->data) { - case ND_OB_ACTIVE: - case ND_OB_SELECT: - case ND_OB_VISIBLE: - case ND_OB_RENDER: - case ND_MODE: - case ND_KEYINGSET: - case ND_FRAME: - case ND_RENDER_OPTIONS: - case ND_SEQUENCER: - case ND_LAYER: - case ND_LAYER_CONTENT: - case ND_WORLD: - case ND_SCENEBROWSE: - ED_region_tag_redraw(ar); - break; - } - break; - case NC_OBJECT: - switch (wmn->data) { - case ND_TRANSFORM: - /* transform doesn't change outliner data */ - break; - case ND_BONE_ACTIVE: - case ND_BONE_SELECT: - case ND_DRAW: - case ND_PARENT: - case ND_OB_SHADING: - ED_region_tag_redraw(ar); - break; - case ND_CONSTRAINT: - switch (wmn->action) { - case NA_ADDED: - case NA_REMOVED: - case NA_RENAME: - ED_region_tag_redraw(ar); - break; - } - break; - case ND_MODIFIER: - /* all modifier actions now */ - ED_region_tag_redraw(ar); - break; - default: - /* Trigger update for NC_OBJECT itself */ - ED_region_tag_redraw(ar); - break; - } - break; - case NC_GROUP: - /* all actions now, todo: check outliner view mode? */ - ED_region_tag_redraw(ar); - break; - case NC_LAMP: - /* For updating light icons, when changing light type */ - if (wmn->data == ND_LIGHTING_DRAW) { - ED_region_tag_redraw(ar); - } - break; - case NC_SPACE: - if (wmn->data == ND_SPACE_OUTLINER) { - ED_region_tag_redraw(ar); - } - break; - case NC_ID: - if (wmn->action == NA_RENAME) { - ED_region_tag_redraw(ar); - } - break; - case NC_MATERIAL: - switch (wmn->data) { - case ND_SHADING_LINKS: - ED_region_tag_redraw(ar); - break; - } - break; - case NC_GEOM: - switch (wmn->data) { - case ND_VERTEX_GROUP: - case ND_DATA: - ED_region_tag_redraw(ar); - break; - } - break; - case NC_ANIMATION: - switch (wmn->data) { - case ND_NLA_ACTCHANGE: - case ND_KEYFRAME: - ED_region_tag_redraw(ar); - break; - case ND_ANIMCHAN: - if (wmn->action == NA_SELECTED) { - ED_region_tag_redraw(ar); - } - break; - } - break; - case NC_GPENCIL: - if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) { - ED_region_tag_redraw(ar); - } - break; - case NC_SCREEN: - if (ELEM(wmn->data, ND_LAYER)) { - ED_region_tag_redraw(ar); - } - break; - case NC_MASK: - if (ELEM(wmn->action, NA_ADDED)) { - ED_region_tag_redraw(ar); - } - break; - case NC_PAINTCURVE: - if (ELEM(wmn->action, NA_ADDED)) { - ED_region_tag_redraw(ar); - } - break; - } - + /* context changes */ + switch (wmn->category) { + case NC_SCENE: + switch (wmn->data) { + case ND_OB_ACTIVE: + case ND_OB_SELECT: + case ND_OB_VISIBLE: + case ND_OB_RENDER: + case ND_MODE: + case ND_KEYINGSET: + case ND_FRAME: + case ND_RENDER_OPTIONS: + case ND_SEQUENCER: + case ND_LAYER: + case ND_LAYER_CONTENT: + case ND_WORLD: + case ND_SCENEBROWSE: + ED_region_tag_redraw(ar); + break; + } + break; + case NC_OBJECT: + switch (wmn->data) { + case ND_TRANSFORM: + /* transform doesn't change outliner data */ + break; + case ND_BONE_ACTIVE: + case ND_BONE_SELECT: + case ND_DRAW: + case ND_PARENT: + case ND_OB_SHADING: + ED_region_tag_redraw(ar); + break; + case ND_CONSTRAINT: + switch (wmn->action) { + case NA_ADDED: + case NA_REMOVED: + case NA_RENAME: + ED_region_tag_redraw(ar); + break; + } + break; + case ND_MODIFIER: + /* all modifier actions now */ + ED_region_tag_redraw(ar); + break; + default: + /* Trigger update for NC_OBJECT itself */ + ED_region_tag_redraw(ar); + break; + } + break; + case NC_GROUP: + /* all actions now, todo: check outliner view mode? */ + ED_region_tag_redraw(ar); + break; + case NC_LAMP: + /* For updating light icons, when changing light type */ + if (wmn->data == ND_LIGHTING_DRAW) { + ED_region_tag_redraw(ar); + } + break; + case NC_SPACE: + if (wmn->data == ND_SPACE_OUTLINER) { + ED_region_tag_redraw(ar); + } + break; + case NC_ID: + if (wmn->action == NA_RENAME) { + ED_region_tag_redraw(ar); + } + break; + case NC_MATERIAL: + switch (wmn->data) { + case ND_SHADING_LINKS: + ED_region_tag_redraw(ar); + break; + } + break; + case NC_GEOM: + switch (wmn->data) { + case ND_VERTEX_GROUP: + case ND_DATA: + ED_region_tag_redraw(ar); + break; + } + break; + case NC_ANIMATION: + switch (wmn->data) { + case ND_NLA_ACTCHANGE: + case ND_KEYFRAME: + ED_region_tag_redraw(ar); + break; + case ND_ANIMCHAN: + if (wmn->action == NA_SELECTED) { + ED_region_tag_redraw(ar); + } + break; + } + break; + case NC_GPENCIL: + if (ELEM(wmn->action, NA_EDITED, NA_SELECTED)) { + ED_region_tag_redraw(ar); + } + break; + case NC_SCREEN: + if (ELEM(wmn->data, ND_LAYER)) { + ED_region_tag_redraw(ar); + } + break; + case NC_MASK: + if (ELEM(wmn->action, NA_ADDED)) { + ED_region_tag_redraw(ar); + } + break; + case NC_PAINTCURVE: + if (ELEM(wmn->action, NA_ADDED)) { + ED_region_tag_redraw(ar); + } + break; + } } -static void outliner_main_region_message_subscribe( - const struct bContext *UNUSED(C), - struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene), - struct bScreen *UNUSED(screen), struct ScrArea *sa, struct ARegion *ar, - struct wmMsgBus *mbus) +static void outliner_main_region_message_subscribe(const struct bContext *UNUSED(C), + struct WorkSpace *UNUSED(workspace), + struct Scene *UNUSED(scene), + struct bScreen *UNUSED(screen), + struct ScrArea *sa, + struct ARegion *ar, + struct wmMsgBus *mbus) { - SpaceOutliner *soops = sa->spacedata.first; - wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { - .owner = ar, - .user_data = ar, - .notify = ED_region_do_msg_notify_tag_redraw, - }; - - if (ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_SCENES)) { - WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw); - } + SpaceOutliner *soops = sa->spacedata.first; + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + + if (ELEM(soops->outlinevis, SO_VIEW_LAYER, SO_SCENES)) { + WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw); + } } - /* ************************ header outliner area region *********************** */ /* add handlers, stuff you only do once or on area/region changes */ static void outliner_header_region_init(wmWindowManager *UNUSED(wm), ARegion *ar) { - ED_region_header_init(ar); + ED_region_header_init(ar); } static void outliner_header_region_draw(const bContext *C, ARegion *ar) { - ED_region_header(C, ar); + ED_region_header(C, ar); } static void outliner_header_region_free(ARegion *UNUSED(ar)) { } -static void outliner_header_region_listener( - wmWindow *UNUSED(win), ScrArea *UNUSED(sa), ARegion *ar, - wmNotifier *wmn, const Scene *UNUSED(scene)) +static void outliner_header_region_listener(wmWindow *UNUSED(win), + ScrArea *UNUSED(sa), + ARegion *ar, + wmNotifier *wmn, + const Scene *UNUSED(scene)) { - /* context changes */ - switch (wmn->category) { - case NC_SCENE: - if (wmn->data == ND_KEYINGSET) { - ED_region_tag_redraw(ar); - } - break; - case NC_SPACE: - if (wmn->data == ND_SPACE_OUTLINER) { - ED_region_tag_redraw(ar); - } - break; - } + /* context changes */ + switch (wmn->category) { + case NC_SCENE: + if (wmn->data == ND_KEYINGSET) { + ED_region_tag_redraw(ar); + } + break; + case NC_SPACE: + if (wmn->data == ND_SPACE_OUTLINER) { + ED_region_tag_redraw(ar); + } + break; + } } /* ******************** default callbacks for outliner space ***************** */ static SpaceLink *outliner_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scene)) { - ARegion *ar; - SpaceOutliner *soutliner; + ARegion *ar; + SpaceOutliner *soutliner; - soutliner = MEM_callocN(sizeof(SpaceOutliner), "initoutliner"); - soutliner->spacetype = SPACE_OUTLINER; - soutliner->filter_id_type = ID_GR; + soutliner = MEM_callocN(sizeof(SpaceOutliner), "initoutliner"); + soutliner->spacetype = SPACE_OUTLINER; + soutliner->filter_id_type = ID_GR; - /* header */ - ar = MEM_callocN(sizeof(ARegion), "header for outliner"); + /* header */ + ar = MEM_callocN(sizeof(ARegion), "header for outliner"); - BLI_addtail(&soutliner->regionbase, ar); - ar->regiontype = RGN_TYPE_HEADER; - ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; + BLI_addtail(&soutliner->regionbase, ar); + ar->regiontype = RGN_TYPE_HEADER; + ar->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; - /* main region */ - ar = MEM_callocN(sizeof(ARegion), "main region for outliner"); + /* main region */ + ar = MEM_callocN(sizeof(ARegion), "main region for outliner"); - BLI_addtail(&soutliner->regionbase, ar); - ar->regiontype = RGN_TYPE_WINDOW; + BLI_addtail(&soutliner->regionbase, ar); + ar->regiontype = RGN_TYPE_WINDOW; - return (SpaceLink *)soutliner; + return (SpaceLink *)soutliner; } /* not spacelink itself */ static void outliner_free(SpaceLink *sl) { - SpaceOutliner *soutliner = (SpaceOutliner *)sl; - - outliner_free_tree(&soutliner->tree); - if (soutliner->treestore) { - BLI_mempool_destroy(soutliner->treestore); - } - if (soutliner->treehash) { - BKE_outliner_treehash_free(soutliner->treehash); - } + SpaceOutliner *soutliner = (SpaceOutliner *)sl; + + outliner_free_tree(&soutliner->tree); + if (soutliner->treestore) { + BLI_mempool_destroy(soutliner->treestore); + } + if (soutliner->treehash) { + BKE_outliner_treehash_free(soutliner->treehash); + } } /* spacetype; init callback */ static void outliner_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(sa)) { - } static SpaceLink *outliner_duplicate(SpaceLink *sl) { - SpaceOutliner *soutliner = (SpaceOutliner *)sl; - SpaceOutliner *soutlinern = MEM_dupallocN(soutliner); + SpaceOutliner *soutliner = (SpaceOutliner *)sl; + SpaceOutliner *soutlinern = MEM_dupallocN(soutliner); - BLI_listbase_clear(&soutlinern->tree); - soutlinern->treestore = NULL; - soutlinern->treehash = NULL; + BLI_listbase_clear(&soutlinern->tree); + soutlinern->treestore = NULL; + soutlinern->treehash = NULL; - return (SpaceLink *)soutlinern; + return (SpaceLink *)soutlinern; } static void outliner_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) { - SpaceOutliner *so = (SpaceOutliner *)slink; - - /* Some early out checks. */ - if (!TREESTORE_ID_TYPE(old_id)) { - return; /* ID type is not used by outilner... */ - } - - if (so->search_tse.id == old_id) { - so->search_tse.id = new_id; - } - - if (so->treestore) { - TreeStoreElem *tselem; - BLI_mempool_iter iter; - bool changed = false; - - BLI_mempool_iternew(so->treestore, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - if (tselem->id == old_id) { - tselem->id = new_id; - changed = true; - } - } - if (so->treehash && changed) { - /* rebuild hash table, because it depends on ids too */ - /* postpone a full rebuild because this can be called many times on-free */ - so->storeflag |= SO_TREESTORE_REBUILD; - } - } + SpaceOutliner *so = (SpaceOutliner *)slink; + + /* Some early out checks. */ + if (!TREESTORE_ID_TYPE(old_id)) { + return; /* ID type is not used by outilner... */ + } + + if (so->search_tse.id == old_id) { + so->search_tse.id = new_id; + } + + if (so->treestore) { + TreeStoreElem *tselem; + BLI_mempool_iter iter; + bool changed = false; + + BLI_mempool_iternew(so->treestore, &iter); + while ((tselem = BLI_mempool_iterstep(&iter))) { + if (tselem->id == old_id) { + tselem->id = new_id; + changed = true; + } + } + if (so->treehash && changed) { + /* rebuild hash table, because it depends on ids too */ + /* postpone a full rebuild because this can be called many times on-free */ + so->storeflag |= SO_TREESTORE_REBUILD; + } + } } /* only called once, from space_api/spacetypes.c */ void ED_spacetype_outliner(void) { - SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype time"); - ARegionType *art; - - st->spaceid = SPACE_OUTLINER; - strncpy(st->name, "Outliner", BKE_ST_MAXNAME); - - st->new = outliner_new; - st->free = outliner_free; - st->init = outliner_init; - st->duplicate = outliner_duplicate; - st->operatortypes = outliner_operatortypes; - st->keymap = outliner_keymap; - st->dropboxes = outliner_dropboxes; - st->id_remap = outliner_id_remap; - - /* regions: main window */ - art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region"); - art->regionid = RGN_TYPE_WINDOW; - art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES; - - art->init = outliner_main_region_init; - art->draw = outliner_main_region_draw; - art->free = outliner_main_region_free; - art->listener = outliner_main_region_listener; - art->message_subscribe = outliner_main_region_message_subscribe; - BLI_addhead(&st->regiontypes, art); - - /* regions: header */ - art = MEM_callocN(sizeof(ARegionType), "spacetype outliner header region"); - art->regionid = RGN_TYPE_HEADER; - art->prefsizey = HEADERY; - art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; - - art->init = outliner_header_region_init; - art->draw = outliner_header_region_draw; - art->free = outliner_header_region_free; - art->listener = outliner_header_region_listener; - BLI_addhead(&st->regiontypes, art); - - BKE_spacetype_register(st); + SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype time"); + ARegionType *art; + + st->spaceid = SPACE_OUTLINER; + strncpy(st->name, "Outliner", BKE_ST_MAXNAME); + + st->new = outliner_new; + st->free = outliner_free; + st->init = outliner_init; + st->duplicate = outliner_duplicate; + st->operatortypes = outliner_operatortypes; + st->keymap = outliner_keymap; + st->dropboxes = outliner_dropboxes; + st->id_remap = outliner_id_remap; + + /* regions: main window */ + art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region"); + art->regionid = RGN_TYPE_WINDOW; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES; + + art->init = outliner_main_region_init; + art->draw = outliner_main_region_draw; + art->free = outliner_main_region_free; + art->listener = outliner_main_region_listener; + art->message_subscribe = outliner_main_region_message_subscribe; + BLI_addhead(&st->regiontypes, art); + + /* regions: header */ + art = MEM_callocN(sizeof(ARegionType), "spacetype outliner header region"); + art->regionid = RGN_TYPE_HEADER; + art->prefsizey = HEADERY; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; + + art->init = outliner_header_region_init; + art->draw = outliner_header_region_draw; + art->free = outliner_header_region_free; + art->listener = outliner_header_region_listener; + BLI_addhead(&st->regiontypes, art); + + BKE_spacetype_register(st); } |