diff options
Diffstat (limited to 'source/blender/editors/space_outliner')
15 files changed, 416 insertions, 44 deletions
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index 4a1e5c1a12c..c31239f0e9c 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -51,6 +51,7 @@ set(SRC tree/tree_display_data.cc tree/tree_display_libraries.cc tree/tree_display_orphaned.cc + tree/tree_display_override_library.cc tree/tree_display_scenes.cc tree/tree_display_sequencer.cc tree/tree_display_view_layer.cc diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c index b3b36811411..7d889eed612 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -818,12 +818,7 @@ static bool datastack_drop_are_types_valid(StackDropData *drop_data) switch (drop_data->drag_tselem->type) { case TSE_MODIFIER_BASE: case TSE_MODIFIER: - if (ob_parent->type == OB_GPENCIL) { - return ob_dst->type == OB_GPENCIL; - } - else if (ob_parent->type != OB_GPENCIL) { - return ob_dst->type != OB_GPENCIL; - } + return (ob_parent->type == OB_GPENCIL) == (ob_dst->type == OB_GPENCIL); break; case TSE_CONSTRAINT_BASE: case TSE_CONSTRAINT: @@ -1008,7 +1003,7 @@ static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropDa drag_te, drop_te, insert_type, &ob->greasepencil_modifiers); ED_object_gpencil_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index); } - else if (ob->type != OB_GPENCIL) { + else { index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->modifiers); ED_object_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index); } @@ -1104,8 +1099,6 @@ static bool collection_drop_init(bContext *C, const wmEvent *event, CollectionDrop *data) { - SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - /* Get collection to drop into. */ TreeElementInsertType insert_type; TreeElement *te = outliner_drop_insert_collection_find(C, event, &insert_type); @@ -1140,7 +1133,7 @@ static bool collection_drop_init(bContext *C, /* Get collection to drag out of. */ ID *parent = drag_id->from_parent; Collection *from_collection = collection_parent_from_ID(parent); - if (event->ctrl || space_outliner->outlinevis == SO_SCENES) { + if (event->ctrl) { from_collection = NULL; } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 0916e106abf..328a787c768 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -1775,6 +1775,87 @@ static void outliner_draw_userbuts(uiBlock *block, } } +static bool outliner_draw_overrides_buts(uiBlock *block, + ARegion *region, + SpaceOutliner *space_outliner, + ListBase *lb, + const bool is_open) +{ + bool any_item_has_warnings = false; + + LISTBASE_FOREACH (TreeElement *, te, lb) { + bool item_has_warnings = false; + const bool do_draw = (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && + te->ys <= region->v2d.cur.ymax); + int but_flag = UI_BUT_DRAG_LOCK; + const char *tip = NULL; + + TreeStoreElem *tselem = TREESTORE(te); + switch (tselem->type) { + case TSE_LIBRARY_OVERRIDE_BASE: { + ID *id = tselem->id; + + if (id->flag & LIB_LIB_OVERRIDE_RESYNC_LEFTOVER) { + item_has_warnings = true; + if (do_draw) { + tip = TIP_( + "This override data-block is not needed anymore, but was detected as user-edited"); + } + } + else if (ID_IS_OVERRIDE_LIBRARY_REAL(id) && ID_REAL_USERS(id) == 0) { + item_has_warnings = true; + if (do_draw) { + tip = TIP_("This override data-block is unused"); + } + } + break; + } + case TSE_LIBRARY_OVERRIDE: { + const bool is_rna_path_valid = (bool)(POINTER_AS_UINT(te->directdata)); + if (!is_rna_path_valid) { + item_has_warnings = true; + if (do_draw) { + tip = TIP_( + "This override property does not exist in current data, it will be removed on " + "next .blend file save"); + } + } + break; + } + default: + break; + } + + const bool any_child_has_warnings = outliner_draw_overrides_buts( + block, + region, + space_outliner, + &te->subtree, + is_open && TSELEM_OPEN(tselem, space_outliner)); + + if (do_draw && + (item_has_warnings || (any_child_has_warnings && !TSELEM_OPEN(tselem, space_outliner)))) { + if (tip == NULL) { + tip = TIP_("Some sub-items require attention"); + } + uiBut *bt = uiDefIconBlockBut(block, + NULL, + NULL, + 1, + ICON_ERROR, + (int)(region->v2d.cur.xmax - OL_TOG_USER_BUTS_STATUS), + te->ys, + UI_UNIT_X, + UI_UNIT_Y, + tip); + UI_but_flag_enable(bt, but_flag); + } + any_item_has_warnings = any_item_has_warnings || item_has_warnings || any_child_has_warnings; + } + + return any_item_has_warnings; +} + static void outliner_draw_rnacols(ARegion *region, int sizex) { View2D *v2d = ®ion->v2d; @@ -2025,7 +2106,7 @@ static void outliner_draw_mode_column_toggle(uiBlock *block, tip); UI_but_func_set(but, outliner_mode_toggle_fn, tselem, NULL); UI_but_flag_enable(but, UI_BUT_DRAG_LOCK); - /* Mode toggling handles it's own undo state because undo steps need to be grouped. */ + /* Mode toggling handles its own undo state because undo steps need to be grouped. */ UI_but_flag_disable(but, UI_BUT_UNDO); if (ID_IS_LINKED(&ob->id)) { @@ -2896,7 +2977,19 @@ static void outliner_draw_iconrow(bContext *C, active = tree_element_type_active_state_get(C, tvc, te, tselem); } - if (!ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION, TSE_R_LAYER, TSE_GP_LAYER)) { + if (!ELEM(tselem->type, + TSE_ID_BASE, + TSE_SOME_ID, + TSE_LAYER_COLLECTION, + TSE_R_LAYER, + TSE_GP_LAYER, + TSE_LIBRARY_OVERRIDE_BASE, + TSE_LIBRARY_OVERRIDE, + TSE_BONE, + TSE_EBONE, + TSE_POSE_CHANNEL, + TSE_POSEGRP, + TSE_DEFGROUP)) { outliner_draw_iconrow_doit(block, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1); } else { @@ -3656,7 +3749,11 @@ void draw_outliner(const bContext *C) } /* Sync selection state from view layer. */ - if (!ELEM(space_outliner->outlinevis, SO_LIBRARIES, SO_DATA_API, SO_ID_ORPHANS) && + if (!ELEM(space_outliner->outlinevis, + SO_LIBRARIES, + SO_OVERRIDES_LIBRARY, + SO_DATA_API, + SO_ID_ORPHANS) && space_outliner->flag & SO_SYNC_SELECT) { outliner_sync_selection(C, space_outliner); } @@ -3703,6 +3800,10 @@ void draw_outliner(const bContext *C) /* draw user toggle columns */ outliner_draw_userbuts(block, region, space_outliner, &space_outliner->tree); } + else if (space_outliner->outlinevis == SO_OVERRIDES_LIBRARY) { + /* Draw overrides status columns. */ + outliner_draw_overrides_buts(block, region, space_outliner, &space_outliner->tree, true); + } else if (restrict_column_width > 0.0f) { /* draw restriction columns */ RestrictPropertiesActive props_active; diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 681f7fab18a..4a070590d55 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -154,7 +154,9 @@ void OUTLINER_OT_highlight_update(wmOperatorType *ot) /** \name Toggle Open/Closed Operator * \{ */ -/* Open or close a tree element, optionally toggling all children recursively */ +/** + * Open or close a tree element, optionally toggling all children recursively. + */ void outliner_item_openclose(SpaceOutliner *space_outliner, TreeElement *te, bool open, @@ -466,7 +468,7 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked id '%s'", id->name); return; } - if (BKE_library_ID_is_indirectly_used(bmain, id) && ID_REAL_USERS(id) <= 1) { + if (ID_REAL_USERS(id) <= 1 && BKE_library_ID_is_indirectly_used(bmain, id)) { BKE_reportf(reports, RPT_WARNING, "Cannot delete id '%s', indirectly used data-blocks need at least one user", @@ -665,6 +667,10 @@ static const EnumPropertyItem *outliner_id_itemf(bContext *C, PropertyRNA *UNUSED(prop), bool *r_free) { + if (C == NULL) { + return DummyRNA_NULL_items; + } + EnumPropertyItem item_tmp = {0}, *item = NULL; int totitem = 0; int i = 0; @@ -1595,8 +1601,10 @@ void OUTLINER_OT_show_one_level(wmOperatorType *ot) /** \name Show Hierarchy Operator * \{ */ -/* Helper function for tree_element_shwo_hierarchy() - - * recursively checks whether subtrees have any objects. */ +/** + * Helper function for #tree_element_shwo_hierarchy() - + * recursively checks whether subtrees have any objects. + */ static int subtree_has_objects(ListBase *lb) { LISTBASE_FOREACH (TreeElement *, te, lb) { diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index f65e273c1b5..fea5ddae16b 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -193,7 +193,7 @@ typedef enum { /* The outliner display modes that support the filter system. * Note: keep it synced with space_outliner.py */ #define SUPPORT_FILTER_OUTLINER(space_outliner_) \ - (ELEM((space_outliner_)->outlinevis, SO_VIEW_LAYER)) + (ELEM((space_outliner_)->outlinevis, SO_VIEW_LAYER, SO_OVERRIDES_LIBRARY)) /* Outliner Searching -- * diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c index 6543a909a41..d78767019b5 100644 --- a/source/blender/editors/space_outliner/outliner_sync.c +++ b/source/blender/editors/space_outliner/outliner_sync.c @@ -356,8 +356,11 @@ static void outliner_sync_selection_from_outliner(Scene *scene, void ED_outliner_select_sync_from_outliner(bContext *C, SpaceOutliner *space_outliner) { /* Don't sync if not checked or in certain outliner display modes */ - if (!(space_outliner->flag & SO_SYNC_SELECT) || - ELEM(space_outliner->outlinevis, SO_LIBRARIES, SO_DATA_API, SO_ID_ORPHANS)) { + if (!(space_outliner->flag & SO_SYNC_SELECT) || ELEM(space_outliner->outlinevis, + SO_LIBRARIES, + SO_OVERRIDES_LIBRARY, + SO_DATA_API, + SO_ID_ORPHANS)) { return; } diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index dc9205106ab..f809bb13b42 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -598,8 +598,14 @@ static uiBlock *merged_element_search_menu(bContext *C, ARegion *region, void *d short menu_width = 10 * UI_UNIT_X; but = uiDefSearchBut( block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, menu_width, UI_UNIT_Y, 0, 0, ""); - UI_but_func_search_set( - but, NULL, merged_element_search_update_fn, data, NULL, merged_element_search_exec_fn, NULL); + UI_but_func_search_set(but, + NULL, + merged_element_search_update_fn, + data, + false, + NULL, + merged_element_search_exec_fn, + NULL); UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT); /* Fake button to hold space for search items */ @@ -699,8 +705,8 @@ static void outliner_object_delete_fn(bContext *C, ReportList *reports, Scene *s reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", ob->id.name + 2); return; } - if (BKE_library_ID_is_indirectly_used(bmain, ob) && ID_REAL_USERS(ob) <= 1 && - ID_EXTRA_USERS(ob) == 0) { + if (ID_REAL_USERS(ob) <= 1 && ID_EXTRA_USERS(ob) == 0 && + BKE_library_ID_is_indirectly_used(bmain, ob)) { BKE_reportf(reports, RPT_WARNING, "Cannot delete object '%s' from scene '%s', indirectly used objects need at " @@ -734,7 +740,7 @@ static void id_local_fn(bContext *C, BKE_lib_id_clear_library_data(bmain, tselem->id); } else { - BKE_main_id_clear_newpoins(bmain); + BKE_main_id_newptr_and_tag_clear(bmain); } } else if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id)) { @@ -840,13 +846,13 @@ static void id_override_library_create_fn(bContext *C, te->store_elem->id->tag |= LIB_TAG_DOIT; } success = BKE_lib_override_library_create( - bmain, CTX_data_scene(C), CTX_data_view_layer(C), id_root, id_reference); + bmain, CTX_data_scene(C), CTX_data_view_layer(C), id_root, id_reference, NULL); } else if (ID_IS_OVERRIDABLE_LIBRARY(id_root)) { success = BKE_lib_override_library_create_from_id(bmain, id_root, true) != NULL; /* Cleanup. */ - BKE_main_id_clear_newpoins(bmain); + BKE_main_id_newptr_and_tag_clear(bmain); BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); } @@ -896,7 +902,7 @@ static void id_override_library_reset_fn(bContext *C, } static void id_override_library_resync_fn(bContext *C, - ReportList *UNUSED(reports), + ReportList *reports, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), @@ -925,7 +931,7 @@ static void id_override_library_resync_fn(bContext *C, } BKE_lib_override_library_resync( - bmain, scene, CTX_data_view_layer(C), id_root, NULL, do_hierarchy_enforce); + bmain, scene, CTX_data_view_layer(C), id_root, NULL, do_hierarchy_enforce, true, reports); WM_event_add_notifier(C, NC_WINDOW, NULL); } @@ -1422,8 +1428,8 @@ static Base *outline_batch_delete_hierarchy( base->object->id.name + 2); return base_next; } - if (BKE_library_ID_is_indirectly_used(bmain, object) && ID_REAL_USERS(object) <= 1 && - ID_EXTRA_USERS(object) == 0) { + if (ID_REAL_USERS(object) <= 1 && ID_EXTRA_USERS(object) == 0 && + BKE_library_ID_is_indirectly_used(bmain, object)) { BKE_reportf(reports, RPT_WARNING, "Cannot delete object '%s' from scene '%s', indirectly used objects need at least " @@ -1873,7 +1879,7 @@ static bool outliner_id_operation_item_poll(bContext *C, case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY: case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE: case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY: - if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id)) { + if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id) && !ID_IS_LINKED(tselem->id)) { return true; } return false; @@ -2263,7 +2269,8 @@ static const EnumPropertyItem outliner_lib_op_type_items[] = { "DELETE", ICON_X, "Delete", - "Delete this library and all its item from Blender - WARNING: no undo"}, + "Delete this library and all its item.\n" + "Warning: No undo"}, {OL_LIB_RELOCATE, "RELOCATE", 0, diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 573fb492613..90389fc1be2 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -908,6 +908,11 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, BLI_assert(!"Expected this ID type to be ported to new Outliner tree-element design"); } } + else if (ELEM(type, TSE_LIBRARY_OVERRIDE_BASE, TSE_LIBRARY_OVERRIDE)) { + if (!te->type) { + BLI_assert(!"Expected override types to be ported to new Outliner tree-element design"); + } + } else { /* Other cases must be caught above. */ BLI_assert(TSE_IS_REAL_ID(tselem)); @@ -1335,7 +1340,7 @@ static void outliner_sort(ListBase *lb) tp->name = te->name; tp->idcode = te->idcode; - if ((tselem->type != TSE_SOME_ID) && tselem->type != TSE_DEFGROUP) { + if (!ELEM(tselem->type, TSE_SOME_ID, TSE_DEFGROUP)) { tp->idcode = 0; /* Don't sort this. */ } if (tselem->type == TSE_ID_BASE) { @@ -1920,5 +1925,5 @@ void outliner_build_tree(Main *mainvar, outliner_filter_tree(space_outliner, view_layer); outliner_restore_scrolling_position(space_outliner, region, &focus); - BKE_main_id_clear_newpoins(mainvar); + BKE_main_id_newptr_and_tag_clear(mainvar); } diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c index 562457c62e9..5feb157bfc8 100644 --- a/source/blender/editors/space_outliner/outliner_utils.c +++ b/source/blender/editors/space_outliner/outliner_utils.c @@ -361,6 +361,7 @@ float outliner_restrict_columns_width(const SpaceOutliner *space_outliner) case SO_DATA_API: case SO_SEQUENCE: case SO_LIBRARIES: + case SO_OVERRIDES_LIBRARY: return 0.0f; case SO_ID_ORPHANS: num_columns = 3; diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 419713035b6..728be1ccaaf 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -155,6 +155,8 @@ static void outliner_main_region_listener(const wmRegionListenerParams *params) case NC_OBJECT: switch (wmn->data) { case ND_TRANSFORM: + ED_region_tag_redraw_no_rebuild(region); + break; case ND_BONE_ACTIVE: case ND_BONE_SELECT: case ND_DRAW: @@ -273,7 +275,7 @@ static void outliner_main_region_message_subscribe(const wmRegionMessageSubscrib .notify = ED_region_do_msg_notify_tag_redraw, }; - if (ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES)) { + if (ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_OVERRIDES_LIBRARY)) { WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw); } } diff --git a/source/blender/editors/space_outliner/tree/tree_display.cc b/source/blender/editors/space_outliner/tree/tree_display.cc index 4395383e838..003afd5bdec 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.cc +++ b/source/blender/editors/space_outliner/tree/tree_display.cc @@ -44,6 +44,9 @@ TreeDisplay *outliner_tree_display_create(eSpaceOutliner_Mode mode, SpaceOutline case SO_ID_ORPHANS: tree_display = new TreeDisplayIDOrphans(*space_outliner); break; + case SO_OVERRIDES_LIBRARY: + tree_display = new TreeDisplayOverrideLibrary(*space_outliner); + break; case SO_VIEW_LAYER: default: tree_display = new TreeDisplayViewLayer(*space_outliner); diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh index b6183050e82..f089a149805 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.hh +++ b/source/blender/editors/space_outliner/tree/tree_display.hh @@ -111,6 +111,24 @@ class TreeDisplayLibraries final : public AbstractTreeDisplay { }; /* -------------------------------------------------------------------- */ +/* Library Overrides Tree-Display. */ + +/** + * \brief Tree-Display for the Library Overrides display mode. + */ +class TreeDisplayOverrideLibrary final : public AbstractTreeDisplay { + public: + TreeDisplayOverrideLibrary(SpaceOutliner &space_outliner); + + ListBase buildTree(const TreeSourceData &source_data) override; + + private: + TreeElement *add_library_contents(Main &, ListBase &, Library *) const; + bool override_library_id_filter_poll(Library *lib, ID *id) const; + short id_filter_get() const; +}; + +/* -------------------------------------------------------------------- */ /* Video Sequencer Tree-Display */ enum SequenceAddOp { diff --git a/source/blender/editors/space_outliner/tree/tree_display_override_library.cc b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc new file mode 100644 index 00000000000..3059f8bfe0c --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc @@ -0,0 +1,204 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "BLI_listbase.h" +#include "BLI_listbase_wrapper.hh" + +#include "BKE_collection.h" +#include "BKE_main.h" + +#include "DNA_collection_types.h" + +#include "BLT_translation.h" + +#include "../outliner_intern.h" +#include "tree_display.hh" + +namespace blender::ed::outliner { + +/* Convenience/readability. */ +template<typename T> using List = ListBaseWrapper<T>; + +TreeDisplayOverrideLibrary::TreeDisplayOverrideLibrary(SpaceOutliner &space_outliner) + : AbstractTreeDisplay(space_outliner) +{ +} + +ListBase TreeDisplayOverrideLibrary::buildTree(const TreeSourceData &source_data) +{ + ListBase tree = {nullptr}; + + { + /* current file first - mainvar provides tselem with unique pointer - not used */ + TreeElement *ten = add_library_contents(*source_data.bmain, tree, nullptr); + TreeStoreElem *tselem; + + if (ten) { + tselem = TREESTORE(ten); + if (!tselem->used) { + tselem->flag &= ~TSE_CLOSED; + } + } + } + + for (ID *id : List<ID>(source_data.bmain->libraries)) { + Library *lib = reinterpret_cast<Library *>(id); + TreeElement *ten = add_library_contents(*source_data.bmain, tree, lib); + /* NULL-check matters, due to filtering there may not be a new element. */ + if (ten) { + lib->id.newid = (ID *)ten; + } + } + + /* make hierarchy */ + for (TreeElement *ten : List<TreeElement>(tree)) { + if (ten == tree.first) { + /* First item is main, skip. */ + continue; + } + + TreeStoreElem *tselem = TREESTORE(ten); + Library *lib = (Library *)tselem->id; + BLI_assert(!lib || (GS(lib->id.name) == ID_LI)); + if (!lib || !lib->parent) { + continue; + } + + TreeElement *parent = (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(&tree, ten); + BLI_addtail(&parent->subtree, ten); + ten->parent = parent; + } + else { + /* Else, make a new copy of the libtree for our parent. */ + TreeElement *dupten = add_library_contents(*source_data.bmain, parent->subtree, lib); + if (dupten) { + dupten->parent = parent; + } + } + } + /* restore newid pointers */ + for (ID *library_id : List<ID>(source_data.bmain->libraries)) { + library_id->newid = nullptr; + } + + return tree; +} + +TreeElement *TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar, + ListBase &lb, + Library *lib) const +{ + const short filter_id_type = id_filter_get(); + + ListBase *lbarray[INDEX_ID_MAX]; + int tot; + if (filter_id_type) { + lbarray[0] = which_libbase(&mainvar, space_outliner_.filter_id_type); + tot = 1; + } + else { + tot = set_listbasepointers(&mainvar, lbarray); + } + + TreeElement *tenlib = nullptr; + for (int a = 0; a < tot; a++) { + if (!lbarray[a] || !lbarray[a]->first) { + continue; + } + + ID *id = nullptr; + + /* check if there's data in current lib */ + for (ID *id_iter : List<ID>(lbarray[a])) { + if (id_iter->lib == lib && ID_IS_OVERRIDE_LIBRARY_REAL(id_iter)) { + id = id_iter; + break; + } + } + + if (id != nullptr) { + if (!tenlib) { + /* Create library tree element on demand, depending if there are any data-blocks. */ + if (lib) { + tenlib = outliner_add_element(&space_outliner_, &lb, lib, nullptr, TSE_SOME_ID, 0); + } + else { + tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0); + tenlib->name = IFACE_("Current File"); + } + } + + /* Create data-block list parent element on demand. */ + if (id != nullptr) { + TreeElement *ten; + + if (filter_id_type) { + ten = tenlib; + } + else { + ten = outliner_add_element( + &space_outliner_, &tenlib->subtree, lbarray[a], nullptr, TSE_ID_BASE, 0); + ten->directdata = lbarray[a]; + ten->name = outliner_idcode_to_plural(GS(id->name)); + } + + for (ID *id : List<ID>(lbarray[a])) { + if (override_library_id_filter_poll(lib, id)) { + TreeElement *override_tree_element = outliner_add_element( + &space_outliner_, &ten->subtree, id, ten, TSE_LIBRARY_OVERRIDE_BASE, 0); + + if (BLI_listbase_is_empty(&override_tree_element->subtree)) { + outliner_free_tree_element(override_tree_element, &ten->subtree); + } + } + } + } + } + } + + return tenlib; +} + +short TreeDisplayOverrideLibrary::id_filter_get() const +{ + if (space_outliner_.filter & SO_FILTER_ID_TYPE) { + return space_outliner_.filter_id_type; + } + return 0; +} + +bool TreeDisplayOverrideLibrary::override_library_id_filter_poll(Library *lib, ID *id) const +{ + if (id->lib != lib) { + return false; + } + + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + return false; + } + + return true; +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc index 6b222e877b1..c5d254242c6 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc @@ -40,13 +40,24 @@ TreeElementOverridesBase::TreeElementOverridesBase(TreeElement &legacy_te, ID &i : AbstractTreeElement(legacy_te), id_(id) { BLI_assert(legacy_te.store_elem->type == TSE_LIBRARY_OVERRIDE_BASE); - legacy_te.name = IFACE_("Library Overrides"); + if (legacy_te.parent != nullptr && + ELEM(legacy_te.parent->store_elem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) + + { + legacy_te.name = IFACE_("Library Overrides"); + } + else { + legacy_te.name = id.name + 2; + } } void TreeElementOverridesBase::expand(SpaceOutliner &space_outliner) const { BLI_assert(id_.override_library != nullptr); + const bool show_system_overrides = (SUPPORT_FILTER_OUTLINER(&space_outliner) && + (space_outliner.filter & SO_FILTER_SHOW_SYSTEM_OVERRIDES) != + 0); PointerRNA idpoin; RNA_id_pointer_create(&id_, &idpoin); @@ -56,15 +67,26 @@ void TreeElementOverridesBase::expand(SpaceOutliner &space_outliner) const for (auto *override_prop : ListBaseWrapper<IDOverrideLibraryProperty>(id_.override_library->properties)) { - if (!BKE_lib_override_rna_property_find( - &idpoin, override_prop, &override_rna_ptr, &override_rna_prop)) { - /* This is fine, override properties list is not always fully up-to-date with current - * RNA/IDProps etc., this gets cleaned up when re-generating the overrides rules, - * no error here. */ - continue; + const bool is_rna_path_valid = BKE_lib_override_rna_property_find( + &idpoin, override_prop, &override_rna_ptr, &override_rna_prop); + if (is_rna_path_valid && !show_system_overrides && + ELEM(override_prop->rna_prop_type, PROP_POINTER, PROP_COLLECTION) && + RNA_struct_is_ID(RNA_property_pointer_type(&override_rna_ptr, override_rna_prop))) { + bool do_continue = true; + for (auto *override_prop_op : + ListBaseWrapper<IDOverrideLibraryPropertyOperation>(override_prop->operations)) { + if ((override_prop_op->flag & IDOVERRIDE_LIBRARY_FLAG_IDPOINTER_MATCH_REFERENCE) == 0) { + do_continue = false; + break; + } + } + + if (do_continue) { + continue; + } } - TreeElementOverridesData data = {id_, *override_prop}; + TreeElementOverridesData data = {id_, *override_prop, is_rna_path_valid}; outliner_add_element( &space_outliner, &legacy_te_.subtree, &data, &legacy_te_, TSE_LIBRARY_OVERRIDE, index++); } @@ -79,6 +101,9 @@ TreeElementOverridesProperty::TreeElementOverridesProperty(TreeElement &legacy_t BLI_assert(legacy_te.store_elem->type == TSE_LIBRARY_OVERRIDE); legacy_te.name = override_prop_.rna_path; + /* Abusing this for now, better way to do it is also pending current refactor of the whole tree + * code to use C++. */ + legacy_te.directdata = POINTER_FROM_UINT(override_data.is_rna_path_valid); } } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh index b5c772f5b33..c3caab8e268 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_overrides.hh +++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.hh @@ -27,6 +27,7 @@ namespace blender::ed::outliner { struct TreeElementOverridesData { ID &id; IDOverrideLibraryProperty &override_property; + bool is_rna_path_valid; }; class TreeElementOverridesBase final : public AbstractTreeElement { |