diff options
5 files changed, 448 insertions, 747 deletions
diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 011a430a1ec..66e6a174003 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -97,6 +97,10 @@ class OUTLINER_MT_context_menu(Menu): layout.separator() + layout.menu("OUTLINER_MT_liboverride") + + layout.separator() + layout.menu("OUTLINER_MT_context_menu_view") layout.separator() @@ -320,6 +324,19 @@ class OUTLINER_MT_asset(Menu): layout.operator("asset.clear", text="Clear Asset (Set Fake User)").set_fake_user = True +class OUTLINER_MT_liboverride(Menu): + bl_label = "Library Override" + + def draw(self, _context): + layout = self.layout + + layout.operator_menu_enum("outliner.liboverride_operation", "selection_set", text="Create").type = 'OVERRIDE_LIBRARY_CREATE_HIERARCHY' + layout.operator_menu_enum("outliner.liboverride_operation", "selection_set", text="Reset").type = 'OVERRIDE_LIBRARY_RESET' + layout.operator_menu_enum("outliner.liboverride_operation", "selection_set", text="Clear").type = 'OVERRIDE_LIBRARY_CLEAR_SINGLE' + + layout.operator_menu_enum("outliner.liboverride_troubleshoot_operation", "type", text="Troubleshoot Hierarchy").selection_set = 'SELECTED' + + class OUTLINER_PT_filter(Panel): bl_space_type = 'OUTLINER' bl_region_type = 'HEADER' @@ -457,6 +474,7 @@ classes = ( OUTLINER_MT_collection_view_layer, OUTLINER_MT_object, OUTLINER_MT_asset, + OUTLINER_MT_liboverride, OUTLINER_MT_context_menu, OUTLINER_MT_context_menu_view, OUTLINER_MT_view_pie, diff --git a/source/blender/blenkernel/BKE_lib_override.h.orig b/source/blender/blenkernel/BKE_lib_override.h.orig deleted file mode 100644 index ee90f0676f7..00000000000 --- a/source/blender/blenkernel/BKE_lib_override.h.orig +++ /dev/null @@ -1,510 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright 2016 Blender Foundation. All rights reserved. */ - -#pragma once - -/** \file - * \ingroup bke - * - * API to manage data-blocks inside of Blender's Main data-base, or as independent runtime-only - * data. - * - * \note `BKE_lib_` files are for operations over data-blocks themselves, although they might - * alter Main as well (when creating/renaming/deleting an ID e.g.). - * - * \section Function Names - * - * \warning Descriptions below is ideal goal, current status of naming does not yet fully follow it - * (this is WIP). - * - * - `BKE_lib_override_library_` should be used for function affecting a single ID. - * - `BKE_lib_override_library_main_` should be used for function affecting the whole collection - * of IDs in a given Main data-base. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -struct BlendFileReadReport; -struct Collection; -struct ID; -struct IDOverrideLibrary; -struct IDOverrideLibraryProperty; -struct IDOverrideLibraryPropertyOperation; -struct Library; -struct Main; -struct Object; -struct PointerRNA; -struct PropertyRNA; -struct ReportList; -struct Scene; -struct ViewLayer; - -/** - * Initialize empty overriding of \a reference_id by \a local_id. - */ -struct IDOverrideLibrary *BKE_lib_override_library_init(struct ID *local_id, - struct ID *reference_id); -/** - * Shallow or deep copy of a whole override from \a src_id to \a dst_id. - */ -void BKE_lib_override_library_copy(struct ID *dst_id, const struct ID *src_id, bool do_full_copy); -/** - * Clear any overriding data from given \a override. - */ -void BKE_lib_override_library_clear(struct IDOverrideLibrary *override, bool do_id_user); -/** - * Free given \a override. - */ -void BKE_lib_override_library_free(struct IDOverrideLibrary **override, bool do_id_user); - -/** - * Return the actual #IDOverrideLibrary data 'controlling' the given `id`, and the actual ID owning - * it. - * - * \note This is especially useful when `id` is a non-real override (e.g. embedded ID like a master - * collection or root node tree, or a shape key). - * -<<<<<<< HEAD - * \param r_owner_id: If given, will be set with the actual ID owning the return liboverride data. -======= - * \param owner_id_hint If not NULL, a potential owner for the given override-embedded `id`. - * \param r_owner_id If given, will be set with the actual ID owning the return liboverride data. ->>>>>>> blender-v3.3-release - */ -IDOverrideLibrary *BKE_lib_override_library_get(struct Main *bmain, - struct ID *id, - struct ID *owner_id_hint, - struct ID **r_owner_id); - -/** - * Check if given ID has some override rules that actually indicate the user edited it. - */ -bool BKE_lib_override_library_is_user_edited(const struct ID *id); - -/** - * Check if given ID is a system override. - */ -bool BKE_lib_override_library_is_system_defined(const struct Main *bmain, const struct ID *id); - -/** - * Check if given Override Property for given ID is animated (through a F-Curve in an Action, or - * from a driver). - * - * \param override_rna_prop: if not NULL, the RNA property matching the given path in the - * `override_prop`. - * \param rnaprop_index: Array in the RNA property, 0 if unknown or irrelevant. - */ -bool BKE_lib_override_library_property_is_animated(const ID *id, - const IDOverrideLibraryProperty *override_prop, - const struct PropertyRNA *override_rna_prop, - const int rnaprop_index); - -/** - * 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, - * and also prevents any automatic re-sync of this local override. - */ -struct ID *BKE_lib_override_library_create_from_id(struct Main *bmain, - struct ID *reference_id, - bool do_tagged_remap); -/** - * Create overridden local copies of all tagged data-blocks in given Main. - * - * \note Set `id->newid` of overridden libs with newly created overrides, - * caller is responsible to clean those pointers before/after usage as needed. - * - * \note By default, it will only remap newly created local overriding data-blocks between - * themselves, to avoid 'enforcing' those overrides into all other usages of the linked data in - * main. You can add more local IDs to be remapped to use new overriding ones by setting their - * LIB_TAG_DOIT tag. - * - * \param owner_library: the library in which the overrides should be created. Besides versioning - * and resync code path, this should always be NULL (i.e. the local .blend file). - * - * \param id_root_reference: the linked ID that is considered as the root of the overridden - * hierarchy. - * - * \param id_hierarchy_root: the override ID that is the root of the hierarchy. May be NULL, in - * which case it is assumed that the given `id_root_reference` is tagged for override, and its - * newly created override will be used as hierarchy root. Must be NULL if - * `id_hierarchy_root_reference` is not NULL. - * - * \param id_hierarchy_root_reference: the linked ID that is the root of the hierarchy. Must be - * tagged for override. May be NULL, in which case it is assumed that the given `id_root_reference` - * is tagged for override, and its newly created override will be used as hierarchy root. Must be - * NULL if `id_hierarchy_root` is not NULL. - * - * \param do_no_main: Create the new override data outside of Main database. - * Used for resyncing of linked overrides. - * - * \param do_fully_editable: if true, tag all created overrides as user-editable by default. - * - * \return \a true on success, \a false otherwise. - */ -bool BKE_lib_override_library_create_from_tag(struct Main *bmain, - struct Library *owner_library, - const struct ID *id_root_reference, - struct ID *id_hierarchy_root, - const struct ID *id_hierarchy_root_reference, - bool do_no_main, - const bool do_fully_editable); -/** - * Advanced 'smart' function to create fully functional overrides. - * - * \note Currently it only does special things if given \a id_root is an object or collection, more - * specific behaviors may be added in the future for other ID types. - * - * \note It will override all IDs tagged with \a LIB_TAG_DOIT, and it does not clear that tag at - * its beginning, so caller code can add extra data-blocks to be overridden as well. - * - * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in - * which case \a scene's master collection children hierarchy is used instead). - * - * \param owner_library: the library in which the overrides should be created. Besides versioning - * and resync code path, this should always be NULL (i.e. the local .blend file). - * - * \param id_root_reference: The linked root ID to create an override from. May be a sub-root of - * the overall hierarchy, in which case calling code is expected to have already tagged required - * 'path' of IDs leading from the given `id_hierarchy_root` to the given `id_root`. - * - * \param id_hierarchy_root_reference: The ID to be used a hierarchy root of the overrides to be - * created. Can be either the linked root ID of the whole override hierarchy, (typically the same - * as `id_root`, unless a sub-part only of the hierarchy is overridden), or the already existing - * override hierarchy root if part of the hierarchy is already overridden. - * - * \param id_instance_hint: Some ID used as hint/reference to do some post-processing after - * overrides have been created, may be NULL. Typically, the Empty object instantiating the linked - * collection we override, currently. - * - * \param r_id_root_override: if not NULL, the override generated for the given \a id_root. - * - * \param do_fully_editable: if true, tag all created overrides as user-editable by default. - * - * \return true if override was successfully created. - */ -bool BKE_lib_override_library_create(struct Main *bmain, - struct Scene *scene, - struct ViewLayer *view_layer, - struct Library *owner_library, - struct ID *id_root_reference, - struct ID *id_hierarchy_root_reference, - struct ID *id_instance_hint, - struct ID **r_id_root_override, - const bool do_fully_editable); -/** - * Create a library override template. - */ -bool BKE_lib_override_library_template_create(struct ID *id); -/** - * Convert a given proxy object into a library override. - * - * \note This is a thin wrapper around \a BKE_lib_override_library_create, only extra work is to - * actually convert the proxy itself into an override first. - * - * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in - * which case \a scene's master collection children hierarchy is used instead). - * \return true if override was successfully created. - */ -bool BKE_lib_override_library_proxy_convert(struct Main *bmain, - struct Scene *scene, - struct ViewLayer *view_layer, - struct Object *ob_proxy); -/** - * Convert all proxy objects into library overrides. - * - * \note Only affects local proxies, linked ones are not affected. - */ -void BKE_lib_override_library_main_proxy_convert(struct Main *bmain, - struct BlendFileReadReport *reports); - -/** - * Find and set the 'hierarchy root' ID pointer of all library overrides in given `bmain`. - * - * NOTE: Cannot be called from `do_versions_after_linking` as this code needs a single complete - * Main database, not a split-by-libraries one. - */ -void BKE_lib_override_library_main_hierarchy_root_ensure(struct Main *bmain); - -/** - * Advanced 'smart' function to resync, re-create fully functional overrides up-to-date with linked - * data, from an existing override hierarchy. - * - * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in - * which case \a scene's master collection children hierarchy is used instead). - * \param id_root: The root liboverride ID to resync from. - * \return true if override was successfully resynced. - */ -bool BKE_lib_override_library_resync(struct Main *bmain, - struct Scene *scene, - struct ViewLayer *view_layer, - struct ID *id_root, - struct Collection *override_resync_residual_storage, - bool do_hierarchy_enforce, - struct BlendFileReadReport *reports); -/** - * Detect and handle required resync of overrides data, when relations between reference linked IDs - * have changed. - * - * This is a fairly complex and costly operation, typically it should be called after - * #BKE_lib_override_library_main_update, which would already detect and tag a lot of cases. - * - * This function will first detect the remaining cases requiring a resync (namely, either when an - * existing linked ID that did not require to be overridden before now would be, or when new IDs - * are added to the hierarchy). - * - * Then it will handle the resync of necessary IDs (through calls to - * #BKE_lib_override_library_resync). - * - * \param view_layer: the active view layer to search instantiated collections in, can be NULL (in - * which case \a scene's master collection children hierarchy is used instead). - */ -void BKE_lib_override_library_main_resync(struct Main *bmain, - struct Scene *scene, - struct ViewLayer *view_layer, - struct BlendFileReadReport *reports); - -/** - * Advanced 'smart' function to delete library overrides (including their existing override - * hierarchy) and remap their usages to their linked reference IDs. - * - * \note All IDs tagged with #LIB_TAG_DOIT will be deleted. - * - * \param id_root: The root liboverride ID to delete. - */ -void BKE_lib_override_library_delete(struct Main *bmain, struct ID *id_root); - -/** - * Make given ID fully local. - * - * \note Only differs from lower-level #BKE_lib_override_library_free in infamous embedded ID - * cases. - */ -void BKE_lib_override_library_make_local(struct ID *id); - -/** - * Find override property from given RNA path, if it exists. - */ -struct IDOverrideLibraryProperty *BKE_lib_override_library_property_find( - struct IDOverrideLibrary *override, const char *rna_path); -/** - * Find override property from given RNA path, or create it if it does not exist. - */ -struct IDOverrideLibraryProperty *BKE_lib_override_library_property_get( - struct IDOverrideLibrary *override, const char *rna_path, bool *r_created); -/** - * Remove and free given \a override_property from given ID \a override. - */ -void BKE_lib_override_library_property_delete(struct IDOverrideLibrary *override, - struct IDOverrideLibraryProperty *override_property); -/** - * Get the RNA-property matching the \a library_prop override property. Used for UI to query - * additional data about the overridden property (e.g. UI name). - * - * \param idpoin: Pointer to the override ID. - * \param library_prop: The library override property to find the matching RNA property for. - * \param r_index: The RNA array flat index (i.e. flattened index in case of multi-dimensional - * array properties). See #RNA_path_resolve_full family of functions for details. - */ -bool BKE_lib_override_rna_property_find(struct PointerRNA *idpoin, - const struct IDOverrideLibraryProperty *library_prop, - struct PointerRNA *r_override_poin, - struct PropertyRNA **r_override_prop, - int *r_index); - -/** - * Find override property operation from given sub-item(s), if it exists. - */ -struct IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_find( - struct IDOverrideLibraryProperty *override_property, - const char *subitem_refname, - const char *subitem_locname, - int subitem_refindex, - int subitem_locindex, - bool strict, - bool *r_strict); -/** - * Find override property operation from given sub-item(s), or create it if it does not exist. - */ -struct IDOverrideLibraryPropertyOperation *BKE_lib_override_library_property_operation_get( - struct IDOverrideLibraryProperty *override_property, - short operation, - const char *subitem_refname, - const char *subitem_locname, - int subitem_refindex, - int subitem_locindex, - bool strict, - bool *r_strict, - bool *r_created); -/** - * Remove and free given \a override_property_operation from given ID \a override_property. - */ -void BKE_lib_override_library_property_operation_delete( - struct IDOverrideLibraryProperty *override_property, - struct IDOverrideLibraryPropertyOperation *override_property_operation); - -/** - * Validate that required data for a given operation are available. - */ -bool BKE_lib_override_library_property_operation_operands_validate( - struct IDOverrideLibraryPropertyOperation *override_property_operation, - struct PointerRNA *ptr_dst, - struct PointerRNA *ptr_src, - struct PointerRNA *ptr_storage, - struct PropertyRNA *prop_dst, - struct PropertyRNA *prop_src, - struct PropertyRNA *prop_storage); - -/** - * Check against potential \a bmain. - */ -void BKE_lib_override_library_validate(struct Main *bmain, - struct ID *id, - struct ReportList *reports); -/** - * Check against potential \a bmain. - */ -void BKE_lib_override_library_main_validate(struct Main *bmain, struct ReportList *reports); - -/** - * Check that status of local data-block is still valid against current reference one. - * - * It means that all overridable, but not overridden, properties' local values must be equal to - * reference ones. Clears #LIB_TAG_OVERRIDE_OK if they do not. - * - * This is typically used to detect whether some property has been changed in local and a new - * #IDOverrideProperty (of #IDOverridePropertyOperation) has to be added. - * - * \return true if status is OK, false otherwise. - */ -bool BKE_lib_override_library_status_check_local(struct Main *bmain, struct ID *local); -/** - * Check that status of reference data-block is still valid against current local one. - * - * It means that all non-overridden properties' local values must be equal to reference ones. - * Clears LIB_TAG_OVERRIDE_OK if they do not. - * - * This is typically used to detect whether some reference has changed and local - * needs to be updated against it. - * - * \return true if status is OK, false otherwise. - */ -bool BKE_lib_override_library_status_check_reference(struct Main *bmain, struct ID *local); - -/** - * Compare local and reference data-blocks and create new override operations as needed, - * or reset to reference values if overriding is not allowed. - * - * \note Defining override operations is only mandatory before saving a `.blend` file on disk - * (not for undo!). - * Knowing that info at runtime is only useful for UI/UX feedback. - * - * \note This is by far the biggest operation (the more time-consuming) of the three so far, - * since it has to go over all properties in depth (all overridable ones at least). - * Generating differential values and applying overrides are much cheaper. - * - * \return true if any library operation was created. - */ -bool BKE_lib_override_library_operations_create(struct Main *bmain, struct ID *local); -/** - * Check all overrides from given \a bmain and create/update overriding operations as needed. - */ -bool BKE_lib_override_library_main_operations_create(struct Main *bmain, bool force_auto); - -/** - * 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, - 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, - bool do_reset_system_override); - -/** - * Set or clear given tag in all operations in that override property data. - */ -void BKE_lib_override_library_operations_tag(struct IDOverrideLibraryProperty *override_property, - short tag, - bool do_set); -/** - * Set or clear given tag in all properties and operations in that override data. - */ -void BKE_lib_override_library_properties_tag(struct IDOverrideLibrary *override, - short tag, - bool do_set); -/** - * Set or clear given tag in all properties and operations in that Main's ID override data. - */ -void BKE_lib_override_library_main_tag(struct Main *bmain, short tag, bool do_set); - -/** - * Remove all tagged-as-unused properties and operations from that ID override data. - */ -void BKE_lib_override_library_id_unused_cleanup(struct ID *local); -/** - * Remove all tagged-as-unused properties and operations from that Main's ID override data. - */ -void BKE_lib_override_library_main_unused_cleanup(struct Main *bmain); - -/** - * Update given override from its reference (re-applying overridden properties). - */ -void BKE_lib_override_library_update(struct Main *bmain, struct ID *local); -/** - * Update all overrides from given \a bmain. - */ -void BKE_lib_override_library_main_update(struct Main *bmain); - -/** - * In case an ID is used by another liboverride ID, user may not be allowed to delete it. - */ -bool BKE_lib_override_library_id_is_user_deletable(struct Main *bmain, struct ID *id); - -/* Storage (.blend file writing) part. */ - -/* For now, we just use a temp main list. */ -typedef struct Main OverrideLibraryStorage; - -/** - * Initialize an override storage. - */ -OverrideLibraryStorage *BKE_lib_override_library_operations_store_init(void); -/** - * Generate suitable 'write' data (this only affects differential override operations). - * - * Note that \a local ID is no more modified by this call, - * all extra data are stored in its temp \a storage_id copy. - */ -struct ID *BKE_lib_override_library_operations_store_start( - struct Main *bmain, OverrideLibraryStorage *override_storage, struct ID *local); -/** - * Restore given ID modified by #BKE_lib_override_library_operations_store_start, to its - * original state. - */ -void BKE_lib_override_library_operations_store_end(OverrideLibraryStorage *override_storage, - struct ID *local); -void BKE_lib_override_library_operations_store_finalize(OverrideLibraryStorage *override_storage); - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/editors/space_outliner/outliner_intern.hh b/source/blender/editors/space_outliner/outliner_intern.hh index 18173b37123..5362782dd84 100644 --- a/source/blender/editors/space_outliner/outliner_intern.hh +++ b/source/blender/editors/space_outliner/outliner_intern.hh @@ -530,6 +530,8 @@ void OUTLINER_OT_operation(struct wmOperatorType *ot); void OUTLINER_OT_scene_operation(struct wmOperatorType *ot); void OUTLINER_OT_object_operation(struct wmOperatorType *ot); void OUTLINER_OT_lib_operation(struct wmOperatorType *ot); +void OUTLINER_OT_liboverride_operation(struct wmOperatorType *ot); +void OUTLINER_OT_liboverride_troubleshoot_operation(struct wmOperatorType *ot); void OUTLINER_OT_id_operation(struct wmOperatorType *ot); void OUTLINER_OT_id_remap(struct wmOperatorType *ot); void OUTLINER_OT_id_copy(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_outliner/outliner_ops.cc b/source/blender/editors/space_outliner/outliner_ops.cc index 8baac45666e..b384c41aa69 100644 --- a/source/blender/editors/space_outliner/outliner_ops.cc +++ b/source/blender/editors/space_outliner/outliner_ops.cc @@ -29,6 +29,8 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_object_operation); WM_operatortype_append(OUTLINER_OT_lib_operation); WM_operatortype_append(OUTLINER_OT_lib_relocate); + WM_operatortype_append(OUTLINER_OT_liboverride_operation); + WM_operatortype_append(OUTLINER_OT_liboverride_troubleshoot_operation); WM_operatortype_append(OUTLINER_OT_id_operation); WM_operatortype_append(OUTLINER_OT_id_delete); WM_operatortype_append(OUTLINER_OT_id_remap); diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc index c408eca654c..1f74a3db0ff 100644 --- a/source/blender/editors/space_outliner/outliner_tools.cc +++ b/source/blender/editors/space_outliner/outliner_tools.cc @@ -453,6 +453,99 @@ static void outliner_do_libdata_operation(bContext *C, }); } +typedef enum eOutlinerLibOpSelectionSet { + /* Only selected items. */ + OUTLINER_LIB_SELECTIONSET_SELECTED, + /* Only content 'inside' selected items (their sub-tree). */ + OUTLINER_LIB_LIB_SELECTIONSET_CONTENT, + /* Combining both options above. */ + OUTLINER_LIB_LIB_SELECTIONSET_SELECTED_AND_CONTENT, +} eOutlinerLibOpSelectionSet; + +static const EnumPropertyItem prop_lib_op_selection_set[] = { + {OUTLINER_LIB_SELECTIONSET_SELECTED, + "SELECTED", + 0, + "Selected", + "Apply the operation over selected data-blocks only"}, + {OUTLINER_LIB_LIB_SELECTIONSET_CONTENT, + "CONTENT", + 0, + "Content", + "Apply the operation over content of the selected items only (the data-blocks in their " + "sub-tree)"}, + {OUTLINER_LIB_LIB_SELECTIONSET_SELECTED_AND_CONTENT, + "SELECTED_AND_CONTENT", + 0, + "Selected & Content", + "Apply the operation over selected data-blocks and all their dependencies"}, + {0, nullptr, 0, nullptr, nullptr}, +}; + +static void outliner_do_libdata_operation_selection_set(bContext *C, + ReportList *reports, + Scene *scene, + SpaceOutliner *space_outliner, + const ListBase &subtree, + const bool has_parent_selected, + outliner_operation_fn operation_fn, + eOutlinerLibOpSelectionSet selection_set, + void *user_data) +{ + const bool do_selected = ELEM(selection_set, + OUTLINER_LIB_SELECTIONSET_SELECTED, + OUTLINER_LIB_LIB_SELECTIONSET_SELECTED_AND_CONTENT); + const bool do_content = ELEM(selection_set, + OUTLINER_LIB_LIB_SELECTIONSET_CONTENT, + OUTLINER_LIB_LIB_SELECTIONSET_SELECTED_AND_CONTENT); + + LISTBASE_FOREACH_MUTABLE (TreeElement *, element, &subtree) { + /* Get needed data out in case element gets freed. */ + TreeStoreElem *tselem = TREESTORE(element); + const ListBase subtree = element->subtree; + + bool is_selected = tselem->flag & TSE_SELECTED; + if ((is_selected && do_selected) || (has_parent_selected && do_content)) { + if (((tselem->type == TSE_SOME_ID) && (element->idcode != 0)) || + tselem->type == TSE_LAYER_COLLECTION) { + TreeStoreElem *tsep = element->parent ? TREESTORE(element->parent) : nullptr; + operation_fn(C, reports, scene, element, tsep, tselem, user_data); + } + } + + /* Don't access element from now on, it may be freed. Note that the open/collapsed state may + * also have been changed in the visitor callback. */ + outliner_do_libdata_operation_selection_set(C, + reports, + scene, + space_outliner, + subtree, + is_selected || has_parent_selected, + operation_fn, + selection_set, + user_data); + } +} + +static void outliner_do_libdata_operation_selection_set(bContext *C, + ReportList *reports, + Scene *scene, + SpaceOutliner *space_outliner, + outliner_operation_fn operation_fn, + eOutlinerLibOpSelectionSet selection_set, + void *user_data) +{ + outliner_do_libdata_operation_selection_set(C, + reports, + scene, + space_outliner, + space_outliner->tree, + false, + operation_fn, + selection_set, + user_data); +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -842,6 +935,20 @@ struct OutlinerLibOverrideData { id_hierarchy_root_reference); value.append(id_root_data); } + void id_root_set(ID *id_hierarchy_root_reference) + { + OutlinerLiboverrideDataIDRoot id_root_data; + id_root_data.id_root_reference = nullptr; + id_root_data.id_hierarchy_root_override = nullptr; + id_root_data.id_instance_hint = nullptr; + id_root_data.is_override_instancing_object = false; + + Vector<OutlinerLiboverrideDataIDRoot> &value = id_hierarchy_roots.lookup_or_add_default( + id_hierarchy_root_reference); + if (value.is_empty()) { + value.append(id_root_data); + } + } }; /* Store 'UUID' of IDs of selected elements in the Outliner tree, before generating the override @@ -860,17 +967,29 @@ static void id_override_library_create_hierarchy_pre_process_fn(bContext *C, const bool do_hierarchy = data->do_hierarchy; ID *id_root_reference = tselem->id; + if (!BKE_idtype_idcode_is_linkable(GS(id_root_reference->name)) || + (id_root_reference->flag & (LIB_EMBEDDED_DATA | LIB_EMBEDDED_DATA_LIB_OVERRIDE)) != 0) { + return; + } + BLI_assert(do_hierarchy); UNUSED_VARS_NDEBUG(do_hierarchy); + printf("Adding %s as selected item to get editable override\n", id_root_reference->name); data->selected_id_uid.add(id_root_reference->session_uuid); + if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root_reference) && !ID_IS_LINKED(id_root_reference)) { + id_root_reference->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED; + return; + } + if (GS(id_root_reference->name) == ID_GR && (tselem->flag & TSE_CLOSED) != 0) { /* If selected element is a (closed) collection, check all of its objects recursively, and also * consider the armature ones as 'selected' (i.e. to not become system overrides). */ Collection *root_collection = reinterpret_cast<Collection *>(id_root_reference); FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (root_collection, object_iter) { if (id_root_reference->lib == object_iter->id.lib && object_iter->type == OB_ARMATURE) { + printf("Adding %s as selected item to get editable override\n", object_iter->id.name); data->selected_id_uid.add(object_iter->id.session_uuid); } } @@ -983,6 +1102,17 @@ static void id_override_library_create_hierarchy_pre_process_fn(bContext *C, return; } + /* While ideally this should not be needed, in practice user almost _never_ wants to actually + * create liboverrides for all data under a selected hierarchy node, and this has currently a + * dreadful consequences over performances (since it would call + * #BKE_lib_override_library_create over _all_ items in the hierarchy). So only the clearing of + * the system override flag is supported for non-selected items for now. + */ + const bool is_selected = tselem->flag & TSE_SELECTED; + if (!is_selected && data->id_hierarchy_roots.contains(id_hierarchy_root_reference)) { + return; + } + data->id_root_add(id_hierarchy_root_reference, id_root_reference, id_instance_hint, @@ -1133,23 +1263,6 @@ static void id_override_library_create_hierarchy_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), @@ -1181,10 +1294,10 @@ static void id_override_library_reset_fn(bContext *C, } } -static void id_override_library_resync_fn(bContext *C, - ReportList *reports, - Scene *scene, - TreeElement *te, +static void id_override_library_resync_fn(bContext *UNUSED(C), + ReportList *UNUSED(reports), + Scene *UNUSED(scene), + TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *user_data) @@ -1192,44 +1305,53 @@ static void id_override_library_resync_fn(bContext *C, BLI_assert(TSE_IS_REAL_ID(tselem)); ID *id_root = tselem->id; OutlinerLibOverrideData *data = static_cast<OutlinerLibOverrideData *>(user_data); - const bool do_hierarchy_enforce = data->do_resync_hierarchy_enforce; - 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 resync library override of data block '%s'", id_root->name); + } - id_root->tag |= LIB_TAG_DOIT; + if (id_root->override_library->hierarchy_root != nullptr) { + id_root = id_root->override_library->hierarchy_root; + } - /* 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; - } + data->id_root_set(id_root); +} - BlendFileReadReport report{}; - report.reports = reports; - BKE_lib_override_library_resync( - bmain, scene, CTX_data_view_layer(C), id_root, nullptr, do_hierarchy_enforce, &report); +/* Resync a hierarchy of library overrides. */ +static void id_override_library_resync_hierarchy_process(bContext *C, + ReportList *reports, + OutlinerLibOverrideData &data) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + const bool do_hierarchy_enforce = data.do_resync_hierarchy_enforce; - WM_event_add_notifier(C, NC_WINDOW, nullptr); - } - else { - CLOG_WARN(&LOG, "Could not resync library override of data block '%s'", id_root->name); + BlendFileReadReport report{}; + report.reports = reports; + + for (auto &&id_hierarchy_root : data.id_hierarchy_roots.keys()) { + BKE_lib_override_library_resync(bmain, + scene, + CTX_data_view_layer(C), + id_hierarchy_root, + nullptr, + do_hierarchy_enforce, + &report); } + + WM_event_add_notifier(C, NC_WINDOW, nullptr); } -static void id_override_library_clear_hierarchy_fn(bContext *C, +static void id_override_library_clear_hierarchy_fn(bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), - TreeElement *te, + TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, - void *UNUSED(user_data)) + void *user_data) { + OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data); + BLI_assert(TSE_IS_REAL_ID(tselem)); ID *id_root = tselem->id; @@ -1238,22 +1360,23 @@ static void id_override_library_clear_hierarchy_fn(bContext *C, return; } - Main *bmain = CTX_data_main(C); + if (id_root->override_library->hierarchy_root != nullptr) { + id_root = id_root->override_library->hierarchy_root; + } - id_root->tag |= LIB_TAG_DOIT; + data->id_root_set(id_root); +} - /* 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; - } +/* Clear (delete) a hierarchy of library overrides. */ +static void id_override_library_clear_hierarchy_process(bContext *C, + ReportList *UNUSED(reports), + OutlinerLibOverrideData &data) +{ + Main *bmain = CTX_data_main(C); - BKE_lib_override_library_delete(bmain, id_root); + for (auto &&id_hierarchy_root : data.id_hierarchy_roots.keys()) { + BKE_lib_override_library_delete(bmain, id_hierarchy_root); + } WM_event_add_notifier(C, NC_WINDOW, nullptr); } @@ -1494,6 +1617,250 @@ static void refreshdrivers_animdata_fn(int UNUSED(event), /** \} */ /* -------------------------------------------------------------------- */ +/** \name Library Overrides Operation Menu. + * \{ */ + +enum eOutlinerLibOverrideOpTypes { + OUTLINER_LIBOVERRIDE_OP_INVALID = 0, + + OUTLINER_LIBOVERRIDE_OP_CREATE_HIERARCHY, + OUTLINER_LIBOVERRIDE_OP_RESET, + OUTLINER_LIBOVERRIDE_OP_CLEAR_SINGLE, + + OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY, + OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY_ENFORCE, + OUTLINER_LIBOVERRIDE_OP_DELETE_HIERARCHY, +}; + +static const EnumPropertyItem prop_liboverride_op_types[] = { + {OUTLINER_LIBOVERRIDE_OP_CREATE_HIERARCHY, + "OVERRIDE_LIBRARY_CREATE_HIERARCHY", + 0, + "Create", + "Make a local override of the selected linked data-blocks, and their hierarchy of " + "dependencies"}, + {OUTLINER_LIBOVERRIDE_OP_RESET, + "OVERRIDE_LIBRARY_RESET", + 0, + "Reset", + "Reset the selected local override to their linked references values"}, + {OUTLINER_LIBOVERRIDE_OP_CLEAR_SINGLE, + "OVERRIDE_LIBRARY_CLEAR_SINGLE", + 0, + "Clear", + "Delete the selected local overrides and relink their usages to the linked data-blocks if " + "possible, else reset them and mark them as non editable"}, + {0, nullptr, 0, nullptr, nullptr}, +}; + +static const EnumPropertyItem prop_liboverride_troubleshoot_op_types[] = { + {OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY, + "OVERRIDE_LIBRARY_RESYNC_HIERARCHY", + 0, + "Resync", + "Rebuild the selected local overrides from their linked references, as well as their " + "hierarchies of dependencies"}, + {OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY_ENFORCE, + "OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE", + 0, + "Resync Enforce", + "Rebuild the selected local overrides from their linked references, as well as their " + "hierarchies of dependencies, enforcing these hierarchies to match the linked data (i.e. " + "ignoring existing overrides on data-blocks pointer properties)"}, + {OUTLINER_LIBOVERRIDE_OP_DELETE_HIERARCHY, + "OVERRIDE_LIBRARY_DELETE_HIERARCHY", + 0, + "Delete", + "Delete the selected local overrides (including their hierarchies of override dependencies) " + "and relink their usages to the linked data-blocks"}, + {0, nullptr, 0, nullptr, nullptr}, +}; + +static bool outliner_liboverride_operation_poll(bContext *C) +{ + if (!outliner_operation_tree_element_poll(C)) { + return false; + } + return true; +} + +static int outliner_liboverride_operation_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); + int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; + + /* check for invalid states */ + if (space_outliner == nullptr) { + return OPERATOR_CANCELLED; + } + + TreeElement *te = get_target_element(space_outliner); + get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel); + + const eOutlinerLibOpSelectionSet selection_set = static_cast<eOutlinerLibOpSelectionSet>( + RNA_enum_get(op->ptr, "selection_set")); + const eOutlinerLibOverrideOpTypes event = static_cast<eOutlinerLibOverrideOpTypes>( + RNA_enum_get(op->ptr, "type")); + switch (event) { + case OUTLINER_LIBOVERRIDE_OP_CREATE_HIERARCHY: { + OutlinerLibOverrideData override_data{}; + override_data.do_hierarchy = true; + override_data.do_fully_editable = false; + + outliner_do_libdata_operation_selection_set( + C, + op->reports, + scene, + space_outliner, + id_override_library_create_hierarchy_pre_process_fn, + selection_set, + &override_data); + + id_override_library_create_hierarchy_process(C, op->reports, override_data); + + ED_undo_push(C, "Overridden Data Hierarchy"); + break; + } + case OUTLINER_LIBOVERRIDE_OP_RESET: { + OutlinerLibOverrideData override_data{}; + outliner_do_libdata_operation_selection_set(C, + op->reports, + scene, + space_outliner, + id_override_library_reset_fn, + selection_set, + &override_data); + ED_undo_push(C, "Reset Overridden Data"); + break; + } + case OUTLINER_LIBOVERRIDE_OP_CLEAR_SINGLE: { + outliner_do_libdata_operation_selection_set(C, + op->reports, + scene, + space_outliner, + id_override_library_clear_single_fn, + selection_set, + nullptr); + ED_undo_push(C, "Clear Overridden Data"); + break; + } + + case OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY: { + OutlinerLibOverrideData override_data{}; + override_data.do_hierarchy = true; + outliner_do_libdata_operation_selection_set(C, + op->reports, + scene, + space_outliner, + id_override_library_resync_fn, + OUTLINER_LIB_SELECTIONSET_SELECTED, + &override_data); + + id_override_library_resync_hierarchy_process(C, op->reports, override_data); + + ED_undo_push(C, "Resync Overridden Data Hierarchy"); + break; + } + case OUTLINER_LIBOVERRIDE_OP_RESYNC_HIERARCHY_ENFORCE: { + OutlinerLibOverrideData override_data{}; + override_data.do_hierarchy = true; + override_data.do_resync_hierarchy_enforce = true; + outliner_do_libdata_operation_selection_set(C, + op->reports, + scene, + space_outliner, + id_override_library_resync_fn, + OUTLINER_LIB_SELECTIONSET_SELECTED, + &override_data); + + id_override_library_resync_hierarchy_process(C, op->reports, override_data); + + ED_undo_push(C, "Resync Overridden Data Hierarchy Enforce"); + break; + } + case OUTLINER_LIBOVERRIDE_OP_DELETE_HIERARCHY: { + OutlinerLibOverrideData override_data{}; + override_data.do_hierarchy = true; + outliner_do_libdata_operation_selection_set(C, + op->reports, + scene, + space_outliner, + id_override_library_clear_hierarchy_fn, + OUTLINER_LIB_SELECTIONSET_SELECTED, + nullptr); + + id_override_library_clear_hierarchy_process(C, op->reports, override_data); + + ED_undo_push(C, "Delete Overridden Data Hierarchy"); + break; + } + default: + /* Invalid - unhandled. */ + break; + } + + /* wrong notifier still... */ + WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr); + + /* XXX: this is just so that outliner is always up to date. */ + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, nullptr); + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_liboverride_operation(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Outliner Library Override Operation"; + ot->idname = "OUTLINER_OT_liboverride_operation"; + + /* callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = outliner_liboverride_operation_exec; + ot->poll = outliner_liboverride_operation_poll; + + ot->flag = 0; + + RNA_def_enum(ot->srna, "type", prop_liboverride_op_types, 0, "Library Override Operation", ""); + ot->prop = RNA_def_enum(ot->srna, + "selection_set", + prop_lib_op_selection_set, + 0, + "Selection Set", + "Over which part of the tree items to apply the operation"); +} + +void OUTLINER_OT_liboverride_troubleshoot_operation(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Outliner Library Override Troubleshoot Operation"; + ot->idname = "OUTLINER_OT_liboverride_troubleshoot_operation"; + + /* callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = outliner_liboverride_operation_exec; + ot->poll = outliner_liboverride_operation_poll; + + ot->flag = 0; + + RNA_def_enum(ot->srna, + "type", + prop_liboverride_troubleshoot_op_types, + 0, + "Library Override Troubleshoot Operation", + ""); + ot->prop = RNA_def_enum(ot->srna, + "selection_set", + prop_lib_op_selection_set, + 0, + "Selection Set", + "Over which part of the tree items to apply the operation"); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Object Operation Utilities * \{ */ @@ -2088,15 +2455,6 @@ enum eOutlinerIdOpTypes { OUTLINER_IDOP_UNLINK, 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_CLEAR_HIERARCHY, - OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE, OUTLINER_IDOP_SINGLE, OUTLINER_IDOP_DELETE, OUTLINER_IDOP_REMAP, @@ -2123,59 +2481,6 @@ static const EnumPropertyItem prop_id_op_types[] = { "Remap Users", "Make all users of selected data-blocks to use instead current (clicked) one"}, RNA_ENUM_ITEM_SEPR, - {OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE, - "OVERRIDE_LIBRARY_CREATE", - 0, - "Make Library Override Single", - "Make a single, out-of-hierarchy local override of this linked data-block - only applies to " - "active Outliner item"}, - {OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY, - "OVERRIDE_LIBRARY_CREATE_HIERARCHY", - 0, - "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, - "Reset Library Override Single", - "Reset this local override to its linked values"}, - {OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY, - "OVERRIDE_LIBRARY_RESET_HIERARCHY", - 0, - "Reset Library Override Hierarchy", - "Reset this local override to its linked values, as well as its hierarchy of dependencies"}, - {OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY, - "OVERRIDE_LIBRARY_RESYNC_HIERARCHY", - 0, - "Resync Library Override Hierarchy", - "Rebuild this local override from its linked reference, as well as its hierarchy of " - "dependencies"}, - {OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE, - "OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE", - 0, - "Resync Library Override Hierarchy Enforce", - "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_CLEAR_SINGLE, - "OVERRIDE_LIBRARY_CLEAR_SINGLE", - 0, - "Clear Library Override Single", - "Delete this local override and relink its usages to the linked data-blocks if possible, " - "else reset it and mark it as non editable"}, - {OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY, - "OVERRIDE_LIBRARY_CLEAR_HIERARCHY", - 0, - "Clear Library Override Hierarchy", - "Delete this local override (including its hierarchy of override dependencies) and relink " - "its usages to the linked data-blocks"}, - RNA_ENUM_ITEM_SEPR, {OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""}, {OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""}, RNA_ENUM_ITEM_SEPR, @@ -2208,33 +2513,6 @@ static bool outliner_id_operation_item_poll(bContext *C, } switch (enum_value) { - case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE: - if (ID_IS_OVERRIDABLE_LIBRARY(tselem->id)) { - return true; - } - return false; - case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY: - if (ID_IS_OVERRIDABLE_LIBRARY(tselem->id) || (ID_IS_LINKED(tselem->id))) { - 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_CLEAR_HIERARCHY: - case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_SINGLE: - if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id) && !ID_IS_LINKED(tselem->id)) { - return true; - } - return false; case OUTLINER_IDOP_SINGLE: if (ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) { return true; @@ -2347,95 +2625,6 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) ED_undo_push(C, "Localized Data"); break; } - case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE: { - OutlinerLibOverrideData override_data{}; - override_data.do_hierarchy = false; - override_data.do_fully_editable = true; - - outliner_do_libdata_operation(C, - op->reports, - scene, - space_outliner, - id_override_library_create_hierarchy_pre_process_fn, - &override_data); - - id_override_library_create_hierarchy_process(C, op->reports, override_data); - - ED_undo_push(C, "Overridden Data"); - break; - } - case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY: { - OutlinerLibOverrideData override_data{}; - override_data.do_hierarchy = true; - override_data.do_fully_editable = U.experimental.use_override_new_fully_editable; - - outliner_do_libdata_operation(C, - op->reports, - scene, - space_outliner, - id_override_library_create_hierarchy_pre_process_fn, - &override_data); - - id_override_library_create_hierarchy_process(C, op->reports, override_data); - - 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, - 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, op->reports, scene, space_outliner, id_override_library_reset_fn, &override_data); - ED_undo_push(C, "Reset Overridden Data"); - break; - } - case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY: { - OutlinerLibOverrideData override_data{}; - override_data.do_hierarchy = true; - outliner_do_libdata_operation( - C, op->reports, scene, space_outliner, id_override_library_reset_fn, &override_data); - ED_undo_push(C, "Reset Overridden Data Hierarchy"); - break; - } - case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY: { - OutlinerLibOverrideData override_data{}; - override_data.do_hierarchy = true; - outliner_do_libdata_operation( - C, op->reports, scene, space_outliner, id_override_library_resync_fn, &override_data); - ED_undo_push(C, "Resync Overridden Data Hierarchy"); - break; - } - case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE: { - OutlinerLibOverrideData override_data{}; - override_data.do_hierarchy = true; - override_data.do_resync_hierarchy_enforce = true; - outliner_do_libdata_operation( - C, op->reports, scene, space_outliner, id_override_library_resync_fn, &override_data); - ED_undo_push(C, "Resync Overridden Data Hierarchy"); - break; - } - case OUTLINER_IDOP_OVERRIDE_LIBRARY_CLEAR_HIERARCHY: { - outliner_do_libdata_operation( - C, op->reports, scene, space_outliner, 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, id_override_library_clear_single_fn, nullptr); - ED_undo_push(C, "Clear Overridden Data Hierarchy"); - break; - } case OUTLINER_IDOP_SINGLE: { /* make single user */ switch (idlevel) { |