[Bf-blender-cvs] [9ca9af2ae43] liboverride-systemoverrides: LibOverride: Add hierarchy creation from IDTemplate UI widget.

Bastien Montagne noreply at git.blender.org
Tue Mar 8 15:53:53 CET 2022


Commit: 9ca9af2ae43b127431e40c77e489ff911c5e7914
Author: Bastien Montagne
Date:   Tue Mar 8 15:51:08 2022 +0100
Branches: liboverride-systemoverrides
https://developer.blender.org/rB9ca9af2ae43b127431e40c77e489ff911c5e7914

LibOverride: Add hierarchy creation from IDTemplate UI widget.

This is fairly tricky to perform, since there is often very limited
contextual information available about the 'active' hierarchy to
override.

This commit is a first step, it is expected to handle decently well
cases like obdata (recreating necessary object and collection
hierarchy), at least in most common cases.

===================================================================

M	source/blender/editors/interface/interface_templates.c

===================================================================

diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 43968e2c986..215198656a8 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -13,6 +13,7 @@
 
 #include "DNA_brush_types.h"
 #include "DNA_cachefile_types.h"
+#include "DNA_collection_types.h"
 #include "DNA_constraint_types.h"
 #include "DNA_curveprofile_types.h"
 #include "DNA_gpencil_modifier_types.h"
@@ -587,6 +588,252 @@ void UI_context_active_but_prop_get_templateID(bContext *C,
   }
 }
 
+static void template_id_liboverride_hierarchy_collection_root_find_recursive(
+    Collection *collection,
+    const int parent_level,
+    Collection **r_collection_parent_best,
+    int *r_parent_level_best)
+{
+  if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY_REAL(collection)) {
+    return;
+  }
+  if (ID_IS_OVERRIDABLE_LIBRARY(collection) || ID_IS_OVERRIDE_LIBRARY_REAL(collection)) {
+    if (parent_level > *r_parent_level_best) {
+      *r_parent_level_best = parent_level;
+      *r_collection_parent_best = collection;
+    }
+  }
+  for (CollectionParent *iter = collection->parents.first; iter != NULL; iter = iter->next) {
+    if (iter->collection->id.lib != collection->id.lib && ID_IS_LINKED(iter->collection)) {
+      continue;
+    }
+    template_id_liboverride_hierarchy_collection_root_find_recursive(
+        iter->collection, parent_level + 1, r_collection_parent_best, r_parent_level_best);
+  }
+}
+
+static void template_id_liboverride_hierarchy_collections_tag_recursive(
+    Collection *root_collection, ID *target_id, const bool do_parents)
+{
+  root_collection->id.tag |= LIB_TAG_DOIT;
+
+  /* Tag all local parents of the root collection, so that usages of the root collection and other
+   * linked ones can be replaced by the local overrides in those parents too. */
+  if (do_parents) {
+    for (CollectionParent *iter = root_collection->parents.first; iter != NULL;
+         iter = iter->next) {
+      if (ID_IS_LINKED(iter->collection)) {
+        continue;
+      }
+      iter->collection->id.tag |= LIB_TAG_DOIT;
+    }
+  }
+
+  for (CollectionChild *iter = root_collection->children.first; iter != NULL; iter = iter->next) {
+    if (iter->collection->id.lib != root_collection->id.lib && ID_IS_LINKED(root_collection)) {
+      continue;
+    }
+    if (ID_IS_LINKED(iter->collection) && iter->collection->id.lib != target_id->lib) {
+      continue;
+    }
+    if (GS(target_id->name) == ID_OB &&
+        !BKE_collection_has_object_recursive(iter->collection, (Object *)target_id)) {
+      continue;
+    }
+    if (GS(target_id->name) == ID_GR &&
+        !BKE_collection_has_collection(iter->collection, (Collection *)target_id)) {
+      continue;
+    }
+    template_id_liboverride_hierarchy_collections_tag_recursive(
+        iter->collection, target_id, false);
+  }
+}
+
+static void template_id_liboverride_hierarchy_create(bContext *C,
+                                                     Main *bmain,
+                                                     TemplateID *template_ui,
+                                                     PointerRNA *idptr,
+                                                     const char **r_undo_push_label)
+{
+  ID *id = idptr->data;
+  ID *owner_id = template_ui->ptr.owner_id;
+
+  /* If the ID is directly linked, do not try to perform a hierarchy override, just override this
+   * single ID, remap this single usage to it, and in case current user is already a hierechy
+   * override, add the new override to this hierarchy. */
+  if (ID_IS_OVERRIDABLE_LIBRARY(id) && !ID_IS_LINKED(owner_id)) {
+    /* Only remap that specific ID usage to overriding local data-block. */
+    ID *override_id = BKE_lib_override_library_create_from_id(bmain, id, false);
+    if (override_id != NULL) {
+      BKE_main_id_newptr_and_tag_clear(bmain);
+
+      if (GS(override_id->name) == ID_OB) {
+        Scene *scene = CTX_data_scene(C);
+        if (!BKE_collection_has_object_recursive(scene->master_collection,
+                                                 (Object *)override_id)) {
+          BKE_collection_object_add_from(bmain, scene, (Object *)id, (Object *)override_id);
+        }
+      }
+
+      /* Assign new pointer, takes care of updates/notifiers. */
+      if (owner_id == NULL || !ID_IS_LINKED(owner_id)) {
+        RNA_id_pointer_create(override_id, idptr);
+      }
+      /* Insert into override hierarchy if possible. */
+      if (owner_id != NULL && !ID_IS_LINKED(owner_id) && ID_IS_OVERRIDE_LIBRARY_REAL(owner_id)) {
+        override_id->override_library->hierarchy_root = owner_id->override_library->hierarchy_root;
+        override_id->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_NO_HIERARCHY;
+      }
+    }
+    *r_undo_push_label = "Make Library Override Single";
+    return;
+  }
+  /* Otherwise, attempt to perform a hierarchy override, based on contextual data available.
+   * NOTE: do not attempt to perform such hierarchy override at all cost, if there is not enough
+   * context, better to abort than create random overrides all over the place. */
+  if (ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(id)) {
+    Object *object_active = CTX_data_active_object(C);
+    if (object_active == NULL && GS(owner_id->name) == ID_OB) {
+      object_active = (Object *)owner_id;
+    }
+    if (object_active != NULL) {
+      if (ID_IS_LINKED(object_active)) {
+        if (object_active->id.lib != id->lib ||
+            !ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(object_active)) {
+          /* The active object is from a different library than the overriden ID, or otherwise
+           * cannot be used in hierarchy. */
+          object_active = NULL;
+        }
+      }
+      else if (!ID_IS_OVERRIDE_LIBRARY_REAL(object_active)) {
+        object_active = NULL;
+      }
+    }
+
+    Collection *collection = CTX_data_collection(C);
+    if (collection == NULL && GS(owner_id->name) == ID_GR) {
+      collection = (Collection *)owner_id;
+    }
+    if (collection != NULL) {
+      if (ID_IS_LINKED(collection)) {
+        if (collection->id.lib != id->lib || !ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(collection)) {
+          /* The active collection is from a different library than the overriden ID, or otherwise
+           * cannot be used in hierarchy. */
+          collection = NULL;
+        }
+        else {
+          int parent_level_best = -1;
+          Collection *collection_parent_best = NULL;
+          template_id_liboverride_hierarchy_collection_root_find_recursive(
+              collection, 0, &collection_parent_best, &parent_level_best);
+          collection = collection_parent_best;
+        }
+      }
+      else if (!ID_IS_OVERRIDE_LIBRARY_REAL(collection)) {
+        collection = NULL;
+      }
+    }
+    if (collection == NULL && object_active != NULL &&
+        (ID_IS_LINKED(object_active) || ID_IS_OVERRIDE_LIBRARY_REAL(object_active))) {
+      LISTBASE_FOREACH (Collection *, collection_iter, &bmain->collections) {
+        if (!(ID_IS_LINKED(collection_iter) || ID_IS_OVERRIDE_LIBRARY_REAL(collection_iter))) {
+          continue;
+        }
+        if (!BKE_collection_has_object_recursive(collection_iter, object_active)) {
+          continue;
+        }
+        int parent_level_best = -1;
+        Collection *collection_parent_best = NULL;
+        template_id_liboverride_hierarchy_collection_root_find_recursive(
+            collection_iter, 0, &collection_parent_best, &parent_level_best);
+        collection = collection_parent_best;
+        break;
+      }
+    }
+
+    ID *id_override = NULL;
+    Scene *scene = CTX_data_scene(C);
+    ViewLayer *view_layer = CTX_data_view_layer(C);
+    switch (GS(id->name)) {
+      case ID_GR:
+        if (collection != NULL && BKE_collection_has_collection(collection, (Collection *)id)) {
+          template_id_liboverride_hierarchy_collections_tag_recursive(collection, id, true);
+          if (object_active != NULL) {
+            object_active->id.tag |= LIB_TAG_DOIT;
+          }
+          BKE_lib_override_library_create(
+              bmain, scene, view_layer, NULL, id, &collection->id, NULL, &id_override);
+        }
+        else if (object_active != NULL && !ID_IS_LINKED(object_active) &&
+                 &object_active->instance_collection->id == id) {
+          object_active->id.tag |= LIB_TAG_DOIT;
+          BKE_lib_override_library_create(bmain,
+                                          scene,
+                                          view_layer,
+                                          id->lib,
+                                          id,
+                                          &object_active->id,
+                                          &object_active->id,
+                                          &id_override);
+        }
+        break;
+      case ID_OB:
+        if (collection != NULL && BKE_collection_has_object_recursive(collection, (Object *)id)) {
+          template_id_liboverride_hierarchy_collections_tag_recursive(collection, id, true);
+          if (object_active != NULL) {
+            object_active->id.tag |= LIB_TAG_DOIT;
+          }
+          BKE_lib_override_library_create(
+              bmain, scene, view_layer, NULL, id, &collection->id, NULL, &id_override);
+        }
+        break;
+      case ID_ME:
+      case ID_CU_LEGACY:
+      case ID_MB:
+      case ID_LT:
+      case ID_LA:
+      case ID_CA:
+      case ID_SPK:
+      case ID_AR:
+      case ID_GD:
+      case ID_CV:
+      case ID_PT:
+      case ID_VO:
+        if (object_active != NULL && object_active->data == id) {
+          if (collection != NULL &&
+              BKE_collection_has_object_recursive(collection, object_active)) {
+            template_id_liboverride_hierarchy_collections_tag_recursive(collection, id, true);
+            if (object_active != NULL) {
+              object_active->id.tag |= LIB_TAG_DOIT;
+            }
+            BKE_lib_override_library_create(
+                bmain, scene, view_layer, NULL, id, &collection->id, NULL, &id_override);
+          }
+          else {
+            o

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list