[Bf-blender-cvs] [d8abac7357b] master: LibOverride: Add hierarchy creation from IDTemplate UI widget.

Bastien Montagne noreply at git.blender.org
Fri Apr 22 18:23:27 CEST 2022


Commit: d8abac7357bf7d3c4e6d73be1836fd725ed173c9
Author: Bastien Montagne
Date:   Tue Mar 8 15:51:08 2022 +0100
Branches: master
https://developer.blender.org/rBd8abac7357bf7d3c4e6d73be1836fd725ed173c9

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 objects and obdata (recreating necessary object and
collection hierarchy, and/or hooking it to a potential existing
hierarchy), at least in most common cases.

Ref: {T95707}.

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

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 a5e2e9353bf..f4d98102d4e 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"
@@ -588,6 +589,234 @@ 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;
+
+  /* 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)) {
+    return;
+  }
+
+  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)) {
+      /* Fully local object cannot be used in override hierarchy either. */
+      object_active = NULL;
+    }
+  }
+
+  Collection *collection_active = CTX_data_collection(C);
+  if (collection_active == NULL && GS(owner_id->name) == ID_GR) {
+    collection_active = (Collection *)owner_id;
+  }
+  if (collection_active != NULL) {
+    if (ID_IS_LINKED(collection_active)) {
+      if (collection_active->id.lib != id->lib ||
+          !ID_IS_OVERRIDABLE_LIBRARY_HIERARCHY(collection_active)) {
+        /* The active collection is from a different library than the overriden ID, or otherwise
+         * cannot be used in hierarchy. */
+        collection_active = NULL;
+      }
+      else {
+        int parent_level_best = -1;
+        Collection *collection_parent_best = NULL;
+        template_id_liboverride_hierarchy_collection_root_find_recursive(
+            collection_active, 0, &collection_parent_best, &parent_level_best);
+        collection_active = collection_parent_best;
+      }
+    }
+    else if (!ID_IS_OVERRIDE_LIBRARY_REAL(collection_active)) {
+      /* Fully local collection cannot be used in override hierarchy either. */
+      collection_active = NULL;
+    }
+  }
+  if (collection_active == NULL && object_active != NULL &&
+      (ID_IS_LINKED(object_active) || ID_IS_OVERRIDE_LIBRARY_REAL(object_active))) {
+    /* If we failed to find a valid 'active' collection so far for our override hierarchy, but do
+     * have a valid 'active' object, try to find a collection from that object. */
+    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_active = 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_active != NULL &&
+          BKE_collection_has_collection(collection_active, (Collection *)id)) {
+        template_id_liboverride_hierarchy_collections_tag_recursive(collection_active, 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_active->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_active != NULL &&
+          BKE_collection_has_object_recursive(collection_active, (Object *)id)) {
+        template_id_liboverride_hierarchy_collections_tag_recursive(collection_active, 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_active->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_active != NULL &&
+            BKE_collection_has_object_recursive(collection_active, object_active)) {
+          template_id_liboverride_hierarchy_collections_tag_recursive(collection_active, 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_active->id, NULL, &id_override);
+        }
+        else {
+          object_active->id.tag |= LIB_TAG_DOIT;
+          BKE_lib_override_library_create(
+              bmain, scene, view_layer, NULL, id, &object_active->id, NULL, &id_override);
+        }
+      }
+      break;
+    case ID_MA:
+    case ID_TE:
+    case ID_IM:
+      break;
+    case ID_WO:
+      break;
+    case ID_PA:
+      break;
+    default:
+      break;
+  }
+  if (id_override != NULL) {
+    id_override->override_library->flag &= ~IDOVERRIDE_LIBRARY_FLAG_SYSTEM_DEFINED;
+    *r_undo_push_label = "Make Library Override Hierarchy";
+
+    WM_event_add_notifier(C, NC_WINDOW, NULL);
+    DEG_relations_tag_update(bmain);
+  }
+}
+
 static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
 {
   TemplateID *template_ui = (TemplateID *)arg_litem;
@@ -637,33 +866,8 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
       if (id) {
         Main *bmain = CTX_data_main(C);
         if (CTX_wm_window(C)->eventstate->modifier & KM_SHIFT) {
-          if (ID_IS_OVERRIDABLE_LIBRARY(id)) {
-            /* Only remap that specific ID usage to overriding local data-block. */
-            ID *override_id = BKE_lib_override_library_create_from_id(bmain, id

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list