LibOverride: Add a dedicated view in the Outliner.
This is a minimal, information-only view currently, listing by default all the override data-blocks, with their user-edited override properties. System-generated overrides (like the overrides of pointers to other override data-blocks) can be shown through a filter option. Finally, potential info or warning messages from (auto-)resync propcess are also shown, as an icon + tooltip next to the affected items. Part of D10855.
This commit is contained in:
parent
8b68a75872
commit
e1ae5bd45f
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1775,6 +1775,88 @@ 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_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");
|
||||
}
|
||||
}
|
||||
|
||||
else 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");
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
@ -2896,7 +2978,13 @@ 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_SOME_ID,
|
||||
TSE_LAYER_COLLECTION,
|
||||
TSE_R_LAYER,
|
||||
TSE_GP_LAYER,
|
||||
TSE_LIBRARY_OVERRIDE_BASE,
|
||||
TSE_LIBRARY_OVERRIDE)) {
|
||||
outliner_draw_iconrow_doit(block, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1);
|
||||
}
|
||||
else {
|
||||
|
@ -3656,7 +3744,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 +3795,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;
|
||||
|
|
|
@ -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 --
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -110,6 +110,24 @@ class TreeDisplayLibraries final : public AbstractTreeDisplay {
|
|||
short id_filter_get() const;
|
||||
};
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* 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 */
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 data-blocks with library overrides and list their overridden properties"},
|
||||
{SO_ID_ORPHANS,
|
||||
"ORPHAN_DATA",
|
||||
ICON_ORPHAN_DATA,
|
||||
|
@ -3588,6 +3593,16 @@ 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 automatically (e.g. to make users of an overridden data-block point to "
|
||||
"the override data, not the original linked data)");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_space_view3d_shading(BlenderRNA *brna)
|
||||
|
|
Loading…
Reference in New Issue