diff options
-rw-r--r-- | source/blender/blenkernel/BKE_lib_override.h | 22 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/lib_override.c | 56 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_edit.cc | 1 | ||||
-rw-r--r-- | source/blender/editors/space_outliner/outliner_tools.cc | 166 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_ID.c | 12 |
5 files changed, 208 insertions, 49 deletions
diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h index daa94031489..2447208b49d 100644 --- a/source/blender/blenkernel/BKE_lib_override.h +++ b/source/blender/blenkernel/BKE_lib_override.h @@ -70,6 +70,14 @@ bool BKE_lib_override_library_is_user_edited(struct ID *id); bool BKE_lib_override_library_is_system_defined(struct Main *bmain, struct ID *id); /** + * Check if given ID is a leaf in its liboverride hierarchy (i.e. if it does not use any other + * override ID). + * + * NOTE: Embedded IDs of override IDs are not considered as leaves. + */ +bool BKE_lib_override_library_is_hierarchy_leaf(struct Main *bmain, struct ID *id); + +/** * Create an overridden local copy of linked reference. * * \note This function is very basic, low-level. It does not consider any hierarchical dependency, @@ -374,12 +382,22 @@ bool BKE_lib_override_library_main_operations_create(struct Main *bmain, bool fo /** * Reset all overrides in given \a id_root, while preserving ID relations. + * + * \param do_reset_system_override If \a true, reset the given ID as a system override one (i.e. + * non-editable). */ -void BKE_lib_override_library_id_reset(struct Main *bmain, struct ID *id_root); +void BKE_lib_override_library_id_reset(struct Main *bmain, + struct ID *id_root, + bool do_reset_system_override); /** * Reset all overrides in given \a id_root and its dependencies, while preserving ID relations. + * + * \param do_reset_system_override If \a true, reset the given ID and all of its descendants in the + * override hierarchy as system override ones (i.e. non-editable). */ -void BKE_lib_override_library_id_hierarchy_reset(struct Main *bmain, struct ID *id_root); +void BKE_lib_override_library_id_hierarchy_reset(struct Main *bmain, + struct ID *id_root, + bool do_reset_system_override); /** * Set or clear given tag in all operations in that override property data. diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index edb23f51308..eb6d9fe358e 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -291,6 +291,32 @@ bool BKE_lib_override_library_is_system_defined(Main *bmain, ID *id) return false; } +static int foreachid_is_hierarchy_leaf_fn(LibraryIDLinkCallbackData *cb_data) +{ + ID *id_owner = cb_data->id_owner; + ID *id = *cb_data->id_pointer; + bool *is_leaf = cb_data->user_data; + + if (id != NULL && ID_IS_OVERRIDE_LIBRARY_REAL(id) && + id->override_library->hierarchy_root == id_owner->override_library->hierarchy_root) { + *is_leaf = false; + return IDWALK_RET_STOP_ITER; + } + return IDWALK_RET_NOP; +} + +bool BKE_lib_override_library_is_hierarchy_leaf(Main *bmain, ID *id) +{ + if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + bool is_leaf = true; + BKE_library_foreach_ID_link( + bmain, id, foreachid_is_hierarchy_leaf_fn, &is_leaf, IDWALK_READONLY); + return is_leaf; + } + + return false; +} + ID *BKE_lib_override_library_create_from_id(Main *bmain, ID *reference_id, const bool do_tagged_remap) @@ -3058,10 +3084,16 @@ bool BKE_lib_override_library_main_operations_create(Main *bmain, const bool for return create_pool_data.changed; } -static bool lib_override_library_id_reset_do(Main *bmain, ID *id_root) +static bool lib_override_library_id_reset_do(Main *bmain, + ID *id_root, + const bool do_reset_system_override) { bool was_op_deleted = false; + if (do_reset_system_override) { + id_root->override_library->flag |= IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED; + } + LISTBASE_FOREACH_MUTABLE ( IDOverrideLibraryProperty *, op, &id_root->override_library->properties) { bool do_op_delete = true; @@ -3117,13 +3149,15 @@ static bool lib_override_library_id_reset_do(Main *bmain, ID *id_root) return was_op_deleted; } -void BKE_lib_override_library_id_reset(Main *bmain, ID *id_root) +void BKE_lib_override_library_id_reset(Main *bmain, + ID *id_root, + const bool do_reset_system_override) { if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { return; } - if (lib_override_library_id_reset_do(bmain, id_root)) { + if (lib_override_library_id_reset_do(bmain, id_root, do_reset_system_override)) { if (id_root->override_library->runtime != NULL && (id_root->override_library->runtime->tag & IDOVERRIDE_LIBRARY_RUNTIME_TAG_NEEDS_RELOAD) != 0) { @@ -3133,7 +3167,9 @@ void BKE_lib_override_library_id_reset(Main *bmain, ID *id_root) } } -static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain, ID *id_root) +static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain, + ID *id_root, + const bool do_reset_system_override) { if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { return; @@ -3142,7 +3178,7 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain, ID *i void **entry_vp = BLI_ghash_lookup_p(bmain->relations->relations_from_pointers, id_root); if (entry_vp == NULL) { /* This ID is not used by nor using any other ID. */ - lib_override_library_id_reset_do(bmain, id_root); + lib_override_library_id_reset_do(bmain, id_root, do_reset_system_override); return; } @@ -3152,7 +3188,7 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain, ID *i return; } - lib_override_library_id_reset_do(bmain, id_root); + lib_override_library_id_reset_do(bmain, id_root, do_reset_system_override); /* This way we won't process again that ID, should we encounter it again through another * relationship hierarchy. */ @@ -3169,17 +3205,19 @@ static void lib_override_library_id_hierarchy_recursive_reset(Main *bmain, ID *i if (*to_id_entry->id_pointer.to != NULL) { ID *to_id = *to_id_entry->id_pointer.to; if (to_id->override_library != NULL) { - lib_override_library_id_hierarchy_recursive_reset(bmain, to_id); + lib_override_library_id_hierarchy_recursive_reset(bmain, to_id, do_reset_system_override); } } } } -void BKE_lib_override_library_id_hierarchy_reset(Main *bmain, ID *id_root) +void BKE_lib_override_library_id_hierarchy_reset(Main *bmain, + ID *id_root, + const bool do_reset_system_override) { BKE_main_relations_create(bmain, 0); - lib_override_library_id_hierarchy_recursive_reset(bmain, id_root); + lib_override_library_id_hierarchy_recursive_reset(bmain, id_root, do_reset_system_override); BKE_main_relations_free(bmain); diff --git a/source/blender/editors/space_outliner/outliner_edit.cc b/source/blender/editors/space_outliner/outliner_edit.cc index ae67e7108bf..d6c5901b546 100644 --- a/source/blender/editors/space_outliner/outliner_edit.cc +++ b/source/blender/editors/space_outliner/outliner_edit.cc @@ -30,6 +30,7 @@ #include "BKE_context.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" +#include "BKE_lib_override.h" #include "BKE_lib_query.h" #include "BKE_lib_remap.h" #include "BKE_main.h" diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc index 6593fb9b6af..22e42c762ca 100644 --- a/source/blender/editors/space_outliner/outliner_tools.cc +++ b/source/blender/editors/space_outliner/outliner_tools.cc @@ -47,6 +47,7 @@ #include "BKE_lib_id.h" #include "BKE_lib_override.h" #include "BKE_lib_query.h" +#include "BKE_lib_remap.h" #include "BKE_main.h" #include "BKE_object.h" #include "BKE_report.h" @@ -1008,6 +1009,23 @@ static void id_override_library_create_hierarchy_post_process(bContext *C, FOREACH_MAIN_ID_END; } +static void id_override_library_toggle_flag_fn(bContext *UNUSED(C), + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *user_data) +{ + BLI_assert(TSE_IS_REAL_ID(tselem)); + ID *id = tselem->id; + + if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + const uint flag = POINTER_AS_UINT(user_data); + id->override_library->flag ^= flag; + } +} + static void id_override_library_reset_fn(bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), @@ -1025,10 +1043,10 @@ static void id_override_library_reset_fn(bContext *C, Main *bmain = CTX_data_main(C); if (do_hierarchy) { - BKE_lib_override_library_id_hierarchy_reset(bmain, id_root); + BKE_lib_override_library_id_hierarchy_reset(bmain, id_root, false); } else { - BKE_lib_override_library_id_reset(bmain, id_root); + BKE_lib_override_library_id_reset(bmain, id_root, false); } WM_event_add_notifier(C, NC_WM | ND_DATACHANGED, nullptr); @@ -1080,40 +1098,76 @@ static void id_override_library_resync_fn(bContext *C, } } -static void id_override_library_delete_fn(bContext *C, - ReportList *UNUSED(reports), - Scene *UNUSED(scene), - TreeElement *te, - TreeStoreElem *UNUSED(tsep), - TreeStoreElem *tselem, - void *UNUSED(user_data)) +static void id_override_library_clear_hierarchy_fn(bContext *C, + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *te, + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) { BLI_assert(TSE_IS_REAL_ID(tselem)); ID *id_root = tselem->id; - if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { - Main *bmain = CTX_data_main(C); + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { + CLOG_WARN(&LOG, "Could not delete library override of data block '%s'", id_root->name); + return; + } - id_root->tag |= LIB_TAG_DOIT; + Main *bmain = CTX_data_main(C); - /* Tag all linked parents in tree hierarchy to be also overridden. */ - while ((te = te->parent) != nullptr) { - if (!TSE_IS_REAL_ID(te->store_elem)) { - continue; - } - if (!ID_IS_OVERRIDE_LIBRARY_REAL(te->store_elem->id)) { - break; - } - te->store_elem->id->tag |= LIB_TAG_DOIT; + id_root->tag |= LIB_TAG_DOIT; + + /* Tag all override parents in tree hierarchy to be also processed. */ + while ((te = te->parent) != nullptr) { + if (!TSE_IS_REAL_ID(te->store_elem)) { + continue; + } + if (!ID_IS_OVERRIDE_LIBRARY_REAL(te->store_elem->id)) { + break; } + te->store_elem->id->tag |= LIB_TAG_DOIT; + } - BKE_lib_override_library_delete(bmain, id_root); + BKE_lib_override_library_delete(bmain, id_root); - WM_event_add_notifier(C, NC_WINDOW, nullptr); + WM_event_add_notifier(C, NC_WINDOW, nullptr); +} + +static void id_override_library_clear_single_fn(bContext *C, + ReportList *reports, + Scene *UNUSED(scene), + TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), + TreeStoreElem *tselem, + void *UNUSED(user_data)) +{ + BLI_assert(TSE_IS_REAL_ID(tselem)); + Main *bmain = CTX_data_main(C); + ID *id = tselem->id; + + if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + BKE_reportf(reports, + RPT_WARNING, + "Cannot clear embedded library override id '%s', only overrides of real " + "data-blocks can be directly deleted", + id->name); + return; + } + + /* If given ID is not using any other override (it's a 'leaf' in the override hierarchy), + * delete it and remap its usages to its linked reference. Otherwise, keep it as a reset system + * override. */ + if (BKE_lib_override_library_is_hierarchy_leaf(bmain, id)) { + BKE_libblock_remap(bmain, id, id->override_library->reference, ID_REMAP_SKIP_INDIRECT_USAGE); + BKE_id_delete(bmain, id); } else { - CLOG_WARN(&LOG, "Could not delete library override of data block '%s'", id_root->name); + BKE_lib_override_library_id_reset(bmain, id, true); } + + WM_event_add_notifier(C, NC_WINDOW, nullptr); + return; } static void id_fake_user_set_fn(bContext *UNUSED(C), @@ -1911,11 +1965,13 @@ enum eOutlinerIdOpTypes { OUTLINER_IDOP_LOCAL, OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE, OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY, + OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE, OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET, OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY, OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY, OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE, - OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY, + OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY, + OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE, OUTLINER_IDOP_SINGLE, OUTLINER_IDOP_DELETE, OUTLINER_IDOP_REMAP, @@ -1954,6 +2010,11 @@ static const EnumPropertyItem prop_id_op_types[] = { "Make Library Override Hierarchy", "Make a local override of this linked data-block, and its hierarchy of dependencies - only " "applies to active Outliner item"}, + {OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE, + "OVERRIDE_LIBRARY_MAKE_EDITABLE", + 0, + "Make Library Override Editable", + "Make the library override data-block editable"}, {OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET, "OVERRIDE_LIBRARY_RESET", 0, @@ -1977,12 +2038,18 @@ static const EnumPropertyItem prop_id_op_types[] = { "Rebuild this local override from its linked reference, as well as its hierarchy of " "dependencies, enforcing that hierarchy to match the linked data (i.e. ignoring exiting " "overrides on data-blocks pointer properties)"}, - {OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY, - "OVERRIDE_LIBRARY_DELETE_HIERARCHY", + {OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY, + "OVERRIDE_LIBRARY_CLEAR_HIERARCHY", 0, - "Delete Library Override Hierarchy", + "Clear Library Override Hierarchy", "Delete this local override (including its hierarchy of override dependencies) and relink " "its usages to the linked data-blocks"}, + {OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE, + "OVERRIDE_LIBRARY_CLEAR_SINGLE", + 0, + "Clear Single Library Override", + "Delete this local override if possible, else reset it and mark it as non editable, and " + "relink its usages to the linked data-blocks"}, {0, "", 0, nullptr, nullptr}, {OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""}, {OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""}, @@ -2026,11 +2093,19 @@ static bool outliner_id_operation_item_poll(bContext *C, return true; } return false; + case OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE: + if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id) && !ID_IS_LINKED(tselem->id)) { + if (tselem->id->override_library->flag & IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED) { + return true; + } + } + return false; case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY: case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY: case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE: - case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY: + case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY: + case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE: if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id) && !ID_IS_LINKED(tselem->id)) { return true; } @@ -2211,6 +2286,18 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) ED_undo_push(C, "Overridden Data Hierarchy"); break; } + case OUTLINER_IDOP_OVERRIDE_LIBRARY_MAKE_EDITABLE: { + outliner_do_libdata_operation(C, + op->reports, + scene, + space_outliner, + &space_outliner->tree, + id_override_library_toggle_flag_fn, + POINTER_FROM_UINT(IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED)); + + ED_undo_push(C, "Make Overridden Data Editable"); + break; + } case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: { OutlinerLibOverrideData override_data{}; outliner_do_libdata_operation(C, @@ -2263,17 +2350,26 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) ED_undo_push(C, "Resync Overridden Data Hierarchy"); break; } - case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY: { - OutlinerLibOverrideData override_data{}; - override_data.do_hierarchy = true; + case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY: { outliner_do_libdata_operation(C, op->reports, scene, space_outliner, &space_outliner->tree, - id_override_library_delete_fn, - &override_data); - ED_undo_push(C, "Delete Overridden Data Hierarchy"); + id_override_library_clear_hierarchy_fn, + nullptr); + ED_undo_push(C, "Clear Overridden Data Hierarchy"); + break; + } + case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE: { + outliner_do_libdata_operation(C, + op->reports, + scene, + space_outliner, + &space_outliner->tree, + id_override_library_clear_single_fn, + nullptr); + ED_undo_push(C, "Clear Overridden Data Hierarchy"); break; } case OUTLINER_IDOP_SINGLE: { diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 5f264a19d47..d3b7e380afa 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -762,7 +762,8 @@ static void rna_ID_override_library_reset(ID *id, IDOverrideLibrary *UNUSED(override_library), Main *bmain, ReportList *reports, - bool do_hierarchy) + bool do_hierarchy, + bool set_system_override) { if (!ID_IS_OVERRIDE_LIBRARY_REAL(id)) { BKE_reportf(reports, RPT_ERROR, "ID '%s' isn't an override", id->name); @@ -770,10 +771,10 @@ static void rna_ID_override_library_reset(ID *id, } if (do_hierarchy) { - BKE_lib_override_library_id_hierarchy_reset(bmain, id); + BKE_lib_override_library_id_hierarchy_reset(bmain, id, set_system_override); } else { - BKE_lib_override_library_id_reset(bmain, id); + BKE_lib_override_library_id_reset(bmain, id, set_system_override); } WM_main_add_notifier(NC_WM | ND_LIB_OVERRIDE_CHANGED, NULL); @@ -1869,6 +1870,11 @@ static void rna_def_ID_override_library(BlenderRNA *brna) true, "", "Also reset all the dependencies of this override to match their reference linked IDs"); + RNA_def_boolean(func, + "set_system_override", + false, + "", + "Reset all user-editable overrides as (non-editable) system overrides"); func = RNA_def_function(srna, "destroy", "rna_ID_override_library_destroy"); RNA_def_function_ui_description( |