Merge branch 'blender-v3.3-release'
Conflicts: source/blender/editors/space_outliner/outliner_tools.cc
This commit is contained in:
commit
4e5f9bbd34
|
@ -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,
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
id_root->tag |= LIB_TAG_DOIT;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
BlendFileReadReport report{};
|
||||
report.reports = reports;
|
||||
BKE_lib_override_library_resync(
|
||||
bmain, scene, CTX_data_view_layer(C), id_root, nullptr, do_hierarchy_enforce, &report);
|
||||
|
||||
WM_event_add_notifier(C, NC_WINDOW, nullptr);
|
||||
}
|
||||
else {
|
||||
if (!ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) {
|
||||
CLOG_WARN(&LOG, "Could not resync library override of data block '%s'", id_root->name);
|
||||
}
|
||||
|
||||
if (id_root->override_library->hierarchy_root != nullptr) {
|
||||
id_root = id_root->override_library->hierarchy_root;
|
||||
}
|
||||
|
||||
data->id_root_set(id_root);
|
||||
}
|
||||
|
||||
static void id_override_library_clear_hierarchy_fn(bContext *C,
|
||||
/* 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;
|
||||
|
||||
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 *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);
|
||||
|
||||
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;
|
||||
if (id_root->override_library->hierarchy_root != nullptr) {
|
||||
id_root = id_root->override_library->hierarchy_root;
|
||||
}
|
||||
|
||||
BKE_lib_override_library_delete(bmain, id_root);
|
||||
data->id_root_set(id_root);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -1493,6 +1616,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) {
|
||||
|
|
Loading…
Reference in New Issue