Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <bastien@blender.org>2021-02-26 19:32:02 +0300
committerBastien Montagne <bastien@blender.org>2021-03-26 14:45:47 +0300
commit7cdf7e992e3494c390ea23d1d9e35f149ea323fc (patch)
treea526d59adc90195bb621017866600d0aa50c198a
parent4425bacec4d639fdc53f4cb8a6817326622b27b7 (diff)
Initial raw liboverride-dedicated view in the Outliner.override-outliner-view
Disclaimer: this is merely a copy of the Libraries (aka blend file) view, with some minor tweaking.
-rw-r--r--release/scripts/startup/bl_ui/space_outliner.py37
-rw-r--r--source/blender/blenkernel/intern/lib_override.c10
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_outliner/outliner_collections.c7
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c134
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h2
-rw-r--r--source/blender/editors/space_outliner/outliner_sync.c7
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c5
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.c1
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c2
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.cc3
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display.hh18
-rw-r--r--source/blender/editors/space_outliner/tree/tree_display_override_library.cc204
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.cc41
-rw-r--r--source/blender/editors/space_outliner/tree/tree_element_overrides.hh1
-rw-r--r--source/blender/makesdna/DNA_ID.h5
-rw-r--r--source/blender/makesdna/DNA_space_types.h3
-rw-r--r--source/blender/makesrna/intern/rna_space.c13
18 files changed, 466 insertions, 28 deletions
diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py
index 5c5a78f3942..1e799379543 100644
--- a/release/scripts/startup/bl_ui/space_outliner.py
+++ b/release/scripts/startup/bl_ui/space_outliner.py
@@ -51,13 +51,13 @@ class OUTLINER_HT_header(Header):
row.prop(space, "use_sync_select", icon='UV_SYNC_SELECT', text="")
row = layout.row(align=True)
- if display_mode in {'SCENES', 'VIEW_LAYER'}:
+ if display_mode in {'SCENES', 'VIEW_LAYER', 'LIBRARY_OVERRIDES'}:
row.popover(
panel="OUTLINER_PT_filter",
text="",
icon='FILTER',
)
- elif display_mode in {'LIBRARIES', 'ORPHAN_DATA'}:
+ if display_mode in {'LIBRARIES', 'LIBRARY_OVERRIDES', 'ORPHAN_DATA'}:
row.prop(space, "use_filter_id_type", text="", icon='FILTER')
sub = row.row(align=True)
sub.active = space.use_filter_id_type
@@ -341,19 +341,26 @@ class OUTLINER_PT_filter(Panel):
col = layout.column(align=True)
col.prop(space, "use_sort_alpha")
- row = layout.row(align=True)
- row.prop(space, "use_sync_select", text="Sync Selection")
+ if display_mode not in {'LIBRARY_OVERRIDES'}:
+ row = layout.row(align=True)
+ row.prop(space, "use_sync_select", text="Sync Selection")
- row = layout.row(align=True)
- row.prop(space, "show_mode_column", text="Show Mode Column")
- layout.separator()
+ row = layout.row(align=True)
+ row.prop(space, "show_mode_column", text="Show Mode Column")
+ layout.separator()
col = layout.column(align=True)
col.label(text="Search")
col.prop(space, "use_filter_complete", text="Exact Match")
col.prop(space, "use_filter_case_sensitive", text="Case Sensitive")
- if display_mode != 'VIEW_LAYER':
+ if display_mode in {'LIBRARY_OVERRIDES'} and bpy.data.libraries:
+ col.separator()
+ row = col.row()
+ row.label(icon='LIBRARY_DATA_OVERRIDE')
+ row.prop(space, "use_filter_lib_override_system", text="System Overrides")
+
+ if display_mode not in {'VIEW_LAYER'}:
return
layout.separator()
@@ -405,10 +412,6 @@ class OUTLINER_PT_filter(Panel):
row = sub.row()
row.label(icon='EMPTY_DATA')
row.prop(space, "use_filter_object_empty", text="Empties")
- row = sub.row()
- if bpy.data.libraries:
- row.label(icon='LIBRARY_DATA_OVERRIDE')
- row.prop(space, "use_filter_lib_override", text="Library Overrides")
if (
bpy.data.curves or
@@ -425,6 +428,16 @@ class OUTLINER_PT_filter(Panel):
row.label(icon='BLANK1')
row.prop(space, "use_filter_object_others", text="Others")
+ if bpy.data.libraries:
+ col.separator()
+ row = col.row()
+ row.label(icon='LIBRARY_DATA_OVERRIDE')
+ row.prop(space, "use_filter_lib_override", text="Library Overrides")
+ row = col.row()
+ row.label(icon='LIBRARY_DATA_OVERRIDE')
+ row.prop(space, "use_filter_lib_override_system", text="System Overrides")
+
+
classes = (
OUTLINER_HT_header,
diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c
index c755d153100..aed3af3927d 100644
--- a/source/blender/blenkernel/intern/lib_override.c
+++ b/source/blender/blenkernel/intern/lib_override.c
@@ -702,6 +702,9 @@ static void lib_override_library_create_post_process(Main *bmain,
base = BKE_view_layer_base_find(view_layer, ob_new);
DEG_id_tag_update_ex(
bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS);
+ if (is_resync) {
+ ob_new->id.flag |= LIB_LIB_OVERRIDE_RESYNC_LEFTOVER;
+ }
}
if (ob_new == (Object *)ob_reference->id.newid && base != NULL) {
@@ -713,6 +716,9 @@ static void lib_override_library_create_post_process(Main *bmain,
view_layer, ob_new, is_resync)) {
BKE_collection_object_add(bmain, collection_new, ob_new);
DEG_id_tag_update_ex(bmain, &ob_new->id, ID_RECALC_TRANSFORM | ID_RECALC_BASE_FLAGS);
+ if (is_resync) {
+ ob_new->id.flag |= LIB_LIB_OVERRIDE_RESYNC_LEFTOVER;
+ }
}
}
}
@@ -729,6 +735,9 @@ static void lib_override_library_create_post_process(Main *bmain,
else {
BKE_collection_object_add_from(bmain, scene, (Object *)id_root, ob_new);
}
+ if (is_resync) {
+ ob_new->id.flag |= LIB_LIB_OVERRIDE_RESYNC_LEFTOVER;
+ }
}
break;
}
@@ -1071,6 +1080,7 @@ bool BKE_lib_override_library_resync(Main *bmain,
/* Otherwise, keep them, user needs to decide whether what to do with them. */
BLI_assert((id->tag & LIB_TAG_DOIT) == 0);
id_fake_user_set(id);
+ id->flag |= LIB_LIB_OVERRIDE_RESYNC_LEFTOVER;
CLOG_INFO(&LOG, 2, "Old override %s is being kept around as it was user-edited", id->name);
}
}
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_collections.c b/source/blender/editors/space_outliner/outliner_collections.c
index 062d2e2b5d1..bb89d7dc3b2 100644
--- a/source/blender/editors/space_outliner/outliner_collections.c
+++ b/source/blender/editors/space_outliner/outliner_collections.c
@@ -166,8 +166,11 @@ void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects)
bool ED_outliner_collections_editor_poll(bContext *C)
{
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
- return (space_outliner != NULL) &&
- ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_LIBRARIES);
+ return (space_outliner != NULL) && ELEM(space_outliner->outlinevis,
+ SO_VIEW_LAYER,
+ SO_SCENES,
+ SO_LIBRARIES,
+ SO_OVERRIDES_LIBRARY);
}
static bool outliner_view_layer_collections_editor_poll(bContext *C)
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 0916e106abf..db661bdd22f 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -1775,6 +1775,116 @@ 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 parent_has_warnings = false;
+
+ LISTBASE_FOREACH (TreeElement *, te, lb) {
+ bool 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_SOME_ID: {
+#if 0
+ if (id->flag & LIB_FAKEUSER) {
+ tip = TIP_("Data-block will be retained using a fake user");
+ }
+ else {
+ tip = TIP_("Data-block has no users and will be deleted");
+ }
+ bt = uiDefIconButBitS(block,
+ UI_BTYPE_ICON_TOGGLE,
+ LIB_FAKEUSER,
+ 1,
+ ICON_FAKE_USER_OFF,
+ (int)(region->v2d.cur.xmax - OL_TOG_USER_BUTS_STATUS),
+ 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);
+#endif
+ break;
+ }
+ case TSE_LIBRARY_OVERRIDE_BASE: {
+ ID *id = tselem->id;
+
+ if (ID_IS_OVERRIDE_LIBRARY_REAL(id) && ID_REAL_USERS(id) == 0) {
+ has_warnings = true;
+ if (do_draw) {
+ tip = TIP_("This override data-block is unused");
+ }
+ }
+
+ else if (id->flag & LIB_LIB_OVERRIDE_RESYNC_LEFTOVER) {
+ has_warnings = true;
+ if (do_draw) {
+ tip = TIP_(
+ "This override data-block is not needed anymore, but was detected as user-edited");
+ }
+ }
+ break;
+ }
+ case TSE_LIBRARY_OVERRIDE: {
+ const bool is_rna_path_valid = (bool)(POINTER_AS_UINT(te->directdata));
+ if (!is_rna_path_valid) {
+ 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 have_children_warnings = outliner_draw_overrides_buts(
+ block,
+ region,
+ space_outliner,
+ &te->subtree,
+ is_open && TSELEM_OPEN(tselem, space_outliner));
+
+ if (do_draw &&
+ (has_warnings || (have_children_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);
+ }
+ parent_has_warnings = parent_has_warnings || has_warnings || have_children_warnings;
+ }
+
+ return parent_has_warnings;
+}
+
static void outliner_draw_rnacols(ARegion *region, int sizex)
{
View2D *v2d = &region->v2d;
@@ -2896,7 +3006,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 +3778,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 +3829,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_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_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 573fb492613..14ab7fd9974 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));
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..5d774049e3e 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -273,7 +273,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..3c561702a43 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 refacor of the whole tree
+ * code to use CPP... */
+ 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 {
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index d88db091cc2..f9524fac72d 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -491,6 +491,11 @@ enum {
* Note that this also applies to shapekeys, even though they are not 100% embedded data...
*/
LIB_EMBEDDED_DATA_LIB_OVERRIDE = 1 << 12,
+ /**
+ * The override data-block appears to not be needed anymore after resync with linked data, but it
+ * was kept around (because e.g. detected as user-edited).
+ */
+ LIB_LIB_OVERRIDE_RESYNC_LEFTOVER = 1 << 13,
};
/**
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index c170e711756..dc8a9bf25e7 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -323,6 +323,8 @@ typedef enum eSpaceOutliner_Filter {
SO_FILTER_NO_CHILDREN = (1 << 4),
SO_FILTER_UNUSED_5 = (1 << 5), /* cleared */
+ /** Show overrides that are defined/controlled by Blender. */
+ SO_FILTER_SHOW_SYSTEM_OVERRIDES = SO_FILTER_UNUSED_5, /* re-use */
SO_FILTER_NO_OB_MESH = (1 << 6),
SO_FILTER_NO_OB_ARMATURE = (1 << 7),
SO_FILTER_NO_OB_EMPTY = (1 << 8),
@@ -391,6 +393,7 @@ typedef enum eSpaceOutliner_Mode {
/* SO_KEYMAP = 13, */ /* deprecated! */
SO_ID_ORPHANS = 14,
SO_VIEW_LAYER = 15,
+ SO_OVERRIDES_LIBRARY = 16,
} eSpaceOutliner_Mode;
/* SpaceOutliner.storeflag */
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index f9b1816e1ba..caf448d3799 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -3399,6 +3399,11 @@ static void rna_def_space_outliner(BlenderRNA *brna)
ICON_RNA,
"Data API",
"Display low level Blender data and its properties"},
+ {SO_OVERRIDES_LIBRARY,
+ "LIBRARY_OVERRIDES",
+ ICON_LIBRARY_DATA_OVERRIDE,
+ "Library Overrides",
+ "Display library overrides data-blocks"},
{SO_ID_ORPHANS,
"ORPHAN_DATA",
ICON_ORPHAN_DATA,
@@ -3588,6 +3593,14 @@ static void rna_def_space_outliner(BlenderRNA *brna)
"Show Library Overrides",
"For libraries with overrides created, show the overridden values");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
+ prop = RNA_def_property(srna, "use_filter_lib_override_system", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "filter", SO_FILTER_SHOW_SYSTEM_OVERRIDES);
+ RNA_def_property_ui_text(prop,
+ "Show System Overrides",
+ "For libraries with overrides created, show the overridden values that "
+ "are defined/controlled by Blender");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
}
static void rna_def_space_view3d_shading(BlenderRNA *brna)