Merge branch 'blender2.8' into tmp-static-override-insertion
authorBastien Montagne <montagne29@wanadoo.fr>
Thu, 3 May 2018 14:02:11 +0000 (16:02 +0200)
committerBastien Montagne <montagne29@wanadoo.fr>
Thu, 3 May 2018 14:02:11 +0000 (16:02 +0200)
13 files changed:
source/blender/blenkernel/BKE_constraint.h
source/blender/blenkernel/intern/constraint.c
source/blender/blenkernel/intern/modifier.c
source/blender/blenloader/intern/readfile.c
source/blender/editors/object/object_constraint.c
source/blender/editors/object/object_modifier.c
source/blender/makesdna/DNA_constraint_types.h
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesrna/RNA_types.h
source/blender/makesrna/intern/rna_access.c
source/blender/makesrna/intern/rna_object.c
source/blender/makesrna/intern/rna_pose.c
source/blender/makesrna/intern/rna_rna.c

index 54ddb61d922b5cdd5759b672608ca2fb2d06f860..18f6301953c80a983763ae6fdef23be1596c8e9c 100644 (file)
@@ -118,6 +118,8 @@ const bConstraintTypeInfo *BKE_constraint_typeinfo_from_type(int type);
 /* Constraint function prototypes */
 void BKE_constraint_unique_name(struct bConstraint *con, struct ListBase *list);
 
+struct bConstraint *BKE_constraint_duplicate_ex(struct bConstraint *src, const int flag, const bool do_extern);
+
 void BKE_constraints_free(struct ListBase *list);
 void BKE_constraints_free_ex(struct ListBase *list, bool do_id_user);
 void BKE_constraints_copy(struct ListBase *dst, const struct ListBase *src, bool do_extern);
index 12a16e9a8b116ec1e69eaf23444a7dc6ee8af926..3ad385bb609d0730cc1b58765de64c40c54fc509 100644 (file)
@@ -4530,7 +4530,7 @@ static bConstraint *add_new_constraint_internal(const char *name, short type)
 
        /* Set up a generic constraint datablock */
        con->type = type;
-       con->flag |= CONSTRAINT_EXPAND;
+       con->flag |= CONSTRAINT_EXPAND | CONSTRAINT_STATICOVERRIDE_LOCAL;
        con->enforce = 1.0f;
 
        /* Determine a basic name, and info */
@@ -4657,6 +4657,43 @@ static void con_fix_copied_refs_cb(bConstraint *UNUSED(con), ID **idpoin, bool i
                id_us_plus(*idpoin);
 }
 
+/** Copies a single constraint's data (\a dst must already be a shallow copy of \a src). */
+static void constraint_copy_data_ex(bConstraint *dst, bConstraint *src, const int flag, const bool do_extern)
+{
+       const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(src);
+
+       /* make a new copy of the constraint's data */
+       dst->data = MEM_dupallocN(dst->data);
+
+       /* only do specific constraints if required */
+       if (cti) {
+               /* perform custom copying operations if needed */
+               if (cti->copy_data)
+                       cti->copy_data(dst, src);
+
+               /* Fix usercounts for all referenced data that need it. */
+               if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
+                       cti->id_looper(dst, con_fix_copied_refs_cb, NULL);
+               }
+
+               /* for proxies we don't want to make extern */
+               if (do_extern) {
+                       /* go over used ID-links for this constraint to ensure that they are valid for proxies */
+                       if (cti->id_looper)
+                               cti->id_looper(dst, con_extern_cb, NULL);
+               }
+       }
+}
+
+/** Allocate and duplicate a single constraint, ouside of any object/pose context. */
+bConstraint *BKE_constraint_duplicate_ex(bConstraint *src, const int flag, const bool do_extern)
+{
+       bConstraint *dst = MEM_dupallocN(src);
+       constraint_copy_data_ex(dst, src, flag, do_extern);
+       dst->next = dst->prev = NULL;
+       return dst;
+}
+
 /* duplicate all of the constraints in a constraint stack */
 void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag, bool do_extern)
 {
@@ -4666,29 +4703,7 @@ void BKE_constraints_copy_ex(ListBase *dst, const ListBase *src, const int flag,
        BLI_duplicatelist(dst, src);
 
        for (con = dst->first, srccon = src->first; con && srccon; srccon = srccon->next, con = con->next) {
-               const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
-
-               /* make a new copy of the constraint's data */
-               con->data = MEM_dupallocN(con->data);
-
-               /* only do specific constraints if required */
-               if (cti) {
-                       /* perform custom copying operations if needed */
-                       if (cti->copy_data)
-                               cti->copy_data(con, srccon);
-
-                       /* Fix usercounts for all referenced data that need it. */
-                       if (cti->id_looper && (flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
-                               cti->id_looper(con, con_fix_copied_refs_cb, NULL);
-                       }
-
-                       /* for proxies we don't want to make extern */
-                       if (do_extern) {
-                               /* go over used ID-links for this constraint to ensure that they are valid for proxies */
-                               if (cti->id_looper)
-                                       cti->id_looper(con, con_extern_cb, NULL);
-                       }
-               }
+               constraint_copy_data_ex(con, srccon, flag, do_extern);
        }
 }
 
index 6722ed2aab10e3a3fb596da84ff1c82ecfde9b54..5153951d2a2a18313ab1185e4b627097c56c9b66 100644 (file)
@@ -132,6 +132,7 @@ ModifierData *modifier_new(int type)
 
        md->type = type;
        md->mode = eModifierMode_Realtime | eModifierMode_Render | eModifierMode_Expanded;
+       md->flag = eModifierFlag_StaticOverride_Local;
 
        if (mti->flags & eModifierTypeFlag_EnableInEditmode)
                md->mode |= eModifierMode_Editmode;
@@ -311,6 +312,7 @@ void modifier_copyData_ex(ModifierData *md, ModifierData *target, const int flag
        const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
 
        target->mode = md->mode;
+       target->flag = md->flag;
 
        if (mti->copyData) {
                mti->copyData(md, target);
index 05a74dc90c24e90b9371167da12dda54b82dcc43..7b8f9db618ddd9eff5a85ff2bceb64c6c7c7f956 100644 (file)
@@ -3391,6 +3391,11 @@ static void lib_link_constraints(FileData *fd, ID *id, ListBase *conlist)
                }
                /* own ipo, all constraints have it */
                con->ipo = newlibadr_us(fd, id->lib, con->ipo); // XXX deprecated - old animation system
+
+               /* If linking from a library, clear 'local' static override flag. */
+               if (id->lib != NULL) {
+                       con->flag &= ~CONSTRAINT_STATICOVERRIDE_LOCAL;
+               }
        }
        
        /* relink all ID-blocks used by the constraints */
@@ -4784,6 +4789,14 @@ static void lib_link_modifiers__linkModifiers(
 static void lib_link_modifiers(FileData *fd, Object *ob)
 {
        modifiers_foreachIDLink(ob, lib_link_modifiers__linkModifiers, fd);
+
+       /* If linking from a library, clear 'local' static override flag. */
+       if (ob->id.lib != NULL) {
+               for (ModifierData *mod = ob->modifiers.first; mod != NULL; mod = mod->next) {
+                       mod->flag &= ~eModifierFlag_StaticOverride_Local;
+               }
+       }
+
 }
 
 static void lib_link_object(FileData *fd, Main *main)
index 95778b73e55af6c66bc469166979d7e8abdc74b3..6a0dedd1d434593ba223613b1bfb6beb4f2068be 100644 (file)
@@ -598,6 +598,11 @@ static int edit_constraint_poll_generic(bContext *C, StructRNA *rna_type)
                return 0;
        }
 
+       if (ID_IS_STATIC_OVERRIDE(ob)) {
+               CTX_wm_operator_poll_msg_set(C, "Cannot edit constraints comming from static override");
+               return (((bConstraint *)ptr.data)->flag & CONSTRAINT_STATICOVERRIDE_LOCAL) != 0;
+       }
+
        return 1;
 }
 
index e2197c58d4965c2c88453009c56e399145f7e7f1..dd04a730542e94292195b673f3e87fb2ca31c803 100644 (file)
@@ -825,9 +825,19 @@ int edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag
        PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type);
        Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C);
        
+       if (!ptr.data) {
+               CTX_wm_operator_poll_msg_set(C, "Context missing 'modifier'");
+               return 0;
+       }
+
        if (!ob || ID_IS_LINKED(ob)) return 0;
        if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) return 0;
        if (ptr.id.data && ID_IS_LINKED(ptr.id.data)) return 0;
+
+       if (ID_IS_STATIC_OVERRIDE(ob)) {
+               CTX_wm_operator_poll_msg_set(C, "Cannot edit modifiers comming from static override");
+               return (((ModifierData *)ptr.data)->flag & eModifierFlag_StaticOverride_Local) != 0;
+       }
        
        return 1;
 }
index 9a87b64ac082019c9d92fa89b14e4d041fb2a9ea..f0f8c3fe2bdebebefe36a78b8bc11cdf010b6b8a 100644 (file)
@@ -526,6 +526,8 @@ typedef enum eBConstraint_Flags {
        CONSTRAINT_OFF = (1<<9),
                /* use bbone curve shape when calculating headtail values */
        CONSTRAINT_BBONE_SHAPE = (1<<10),
+               /* That constraint has been inserted in local override (i.e. it can be fully edited!). */
+       CONSTRAINT_STATICOVERRIDE_LOCAL = (1 << 11),
 } eBConstraint_Flags;
 
 /* bConstraint->ownspace/tarspace */
index a7f9acb8a42ac160ad665120dbe43d7c46921ca5..cfa101b0b6eac92ac45fdd674c85a994ab4ae58b 100644 (file)
@@ -105,7 +105,9 @@ typedef struct ModifierData {
        struct ModifierData *next, *prev;
 
        int type, mode;
-       int stackindex, pad;
+       int stackindex;
+       short flag;
+       short pad;
        char name[64];  /* MAX_NAME */
 
        /* XXX for timing info set by caller... solve later? (ton) */
@@ -114,6 +116,11 @@ typedef struct ModifierData {
        char *error;
 } ModifierData;
 
+typedef enum {
+       /* This modifier has been inserted in local override, and hence can be fully edited. */
+       eModifierFlag_StaticOverride_Local  = (1 << 0),
+} ModifierFlag;
+
 typedef enum {
        eSubsurfModifierFlag_Incremental  = (1 << 0),
        eSubsurfModifierFlag_DebugIncr    = (1 << 1),
index 77d9aabd661dce8ede540c8255902047343b421f..5d6f309ad6557323dba62206238d8c5216a3f98f 100644 (file)
@@ -158,7 +158,7 @@ typedef enum PropertySubType {
 
 /* Make sure enums are updated with these */
 /* HIGHEST FLAG IN USE: 1 << 31
- * FREE FLAGS: 9, 11, 13, 14, 15, 30 */
+ * FREE FLAGS: 11, 13, 14, 15, 30 */
 typedef enum PropertyFlag {
        /* editable means the property is editable in the user
         * interface, properties are editable by default except
@@ -178,6 +178,8 @@ typedef enum PropertyFlag {
 
        /* Means the property can be overriden by a local 'proxy' of some linked datablock. */
        PROP_OVERRIDABLE_STATIC      = (1 << 2),
+       /* The property supports insertion (collections only). */
+       PROP_OVERRIDABLE_STATIC_INSERTION = (1 << 9),
 
        /* Forbid usage of this property in comparison (& hence override) code.
         * Useful e.g. for collections of data like mesh's geometry, particles, etc. */
index d70309dadb894f94f2c7cb84ae3927f2e6ec7736..7bf00ef65f6db7dc37b8e17133ce77fd07ef7956 100644 (file)
@@ -34,6 +34,8 @@
 
 #include "DNA_ID.h"
 #include "DNA_scene_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_modifier_types.h"
 #include "DNA_windowmanager_types.h"
 
 #include "BLI_blenlib.h"
@@ -1966,9 +1968,24 @@ bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop)
 
 /** \note Does not take into account editable status, this has to be checked separately
  * (using RNA_property_edtiable_flag() usually). */
-bool RNA_property_overridable_get(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
+bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
 {
        if (prop->magic == RNA_MAGIC) {
+               /* Special handling for insertions of constraints or modifiers... */
+               /* TODO Note We may want to add a more generic system to RNA (like a special property in struct of items)
+                * if we get more overrideable collections, for now we can live with those special-cases handling I think. */
+               if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
+                       bConstraint *con = ptr->data;
+                       if (con->flag & CONSTRAINT_STATICOVERRIDE_LOCAL) {
+                               return true;
+                       }
+               }
+               else if (RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
+                       ModifierData *mod = ptr->data;
+                       if (mod->flag & eModifierFlag_StaticOverride_Local) {
+                               return true;
+                       }
+               }
                /* If this is a RNA-defined property (real or 'virtual' IDProp), we want to use RNA prop flag. */
                return !(prop->flag & PROP_NO_COMPARISON) && (prop->flag & PROP_OVERRIDABLE_STATIC);
        }
@@ -7684,12 +7701,20 @@ bool RNA_struct_override_store(
 static void rna_property_override_apply_ex(
         PointerRNA *ptr_local, PointerRNA *ptr_override, PointerRNA *ptr_storage,
         PropertyRNA *prop_local, PropertyRNA *prop_override, PropertyRNA *prop_storage,
-        IDOverrideStaticProperty *op)
+        IDOverrideStaticProperty *op, const bool do_insert)
 {
        for (IDOverrideStaticPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+               if (!do_insert != !ELEM(opop->operation, IDOVERRIDESTATIC_OP_INSERT_AFTER, IDOVERRIDESTATIC_OP_INSERT_BEFORE)) {
+                       if (!do_insert) {
+                               printf("Skipping insert override operations in first pass (%s)!\n", op->rna_path);
+                       }
+                       continue;
+               }
                if (!rna_property_override_operation_apply(ptr_local, ptr_override, ptr_storage,
                                                           prop_local, prop_override, prop_storage, opop))
                {
+                       /* TODO No assert here, would be much much better to just report as warning,
+                        * failing override applications will probably be fairly common! */
                        BLI_assert(0);
                }
        }
@@ -7703,32 +7728,38 @@ void RNA_struct_override_apply(
 #ifdef DEBUG_OVERRIDE_TIMEIT
        TIMEIT_START_AVERAGED(RNA_struct_override_apply);
 #endif
-       for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
-               /* Simplified for now! */
-               PointerRNA data_override, data_local;
-               PropertyRNA *prop_override, *prop_local;
+       /* Note: Applying insert operations in a separate pass is mandatory.
+        * We could optimize this later, but for now, as inneficient as it is, don't think this is a critical point.
+        */
+       bool do_insert = false;
+       for (int i = 0; i < 2; i++, do_insert = true) {
+               for (IDOverrideStaticProperty *op = override->properties.first; op; op = op->next) {
+                       /* Simplified for now! */
+                       PointerRNA data_override, data_local;
+                       PropertyRNA *prop_override, *prop_local;
+
+                       if (RNA_path_resolve_property(ptr_local, op->rna_path, &data_local, &prop_local) &&
+                           RNA_path_resolve_property(ptr_override, op->rna_path, &data_override, &prop_override))
+                       {
+                               PointerRNA data_storage;
+                               PropertyRNA *prop_storage = NULL;
 
-               if (RNA_path_resolve_property(ptr_local, op->rna_path, &data_local, &prop_local) &&
-                   RNA_path_resolve_property(ptr_override, op->rna_path, &data_override, &prop_override))
-               {
-                       PointerRNA data_storage;
-                       PropertyRNA *prop_storage = NULL;
+                               /* It is totally OK if this does not success, only a subset of override operations actually need storage. */
+                               if (ptr_storage && (ptr_storage->id.data != NULL)) {
+                                       RNA_path_resolve_property(ptr_storage, op->rna_path, &data_storage, &prop_storage);
+                               }
 
-                       /* It is totally OK if this does not success, only a subset of override operations actually need storage. */
-                       if (ptr_storage && (ptr_storage->id.data != NULL)) {
-                               RNA_path_resolve_property(ptr_storage, op->rna_path, &data_storage, &prop_storage);
+                               rna_property_override_apply_ex(
+                                           &data_local, &data_override, prop_storage ? &data_storage : NULL,
+                                           prop_local, prop_override, prop_storage, op, do_insert);
                        }
-
-                       rna_property_override_apply_ex(
-                                   &data_local, &data_override, prop_storage ? &data_storage : NULL,
-                                   prop_local, prop_override, prop_storage, op);
-               }
 #ifndef NDEBUG
-               else {
-                       printf("Failed to apply static override operation to '%s.%s' (could not resolve some properties)\n",
-                              ((ID *)ptr_override->id.data)->name, op->rna_path);
-               }
+                       else {
+                               printf("Failed to apply static override operation to '%s.%s' (could not resolve some properties)\n",
+                                      ((ID *)ptr_override->id.data)->name, op->rna_path);
+                       }
 #endif
+               }
        }
 #ifdef DEBUG_OVERRIDE_TIMEIT
        TIMEIT_END_AVERAGED(RNA_struct_override_apply);
index 464fcc3856e957f305996d31e777dac8acdb79b0..079f761ccdd5ac9fa2a0fed347444cb14d5914a8 100644 (file)
@@ -174,6 +174,7 @@ const EnumPropertyItem rna_enum_object_axis_items[] = {
 
 #include "DNA_key_types.h"
 #include "DNA_constraint_types.h"
+#include "DNA_ID.h"
 #include "DNA_lattice_types.h"
 #include "DNA_node_types.h"
 
@@ -187,6 +188,7 @@ const EnumPropertyItem rna_enum_object_axis_items[] = {
 #include "BKE_object.h"
 #include "BKE_material.h"
 #include "BKE_mesh.h"
+#include "BKE_modifier.h"
 #include "BKE_particle.h"
 #include "BKE_scene.h"
 #include "BKE_deform.h"
@@ -1133,6 +1135,54 @@ static void rna_Object_constraints_clear(Object *object)
        WM_main_add_notifier(NC_OBJECT | ND_CONSTRAINT | NA_REMOVED, object);
 }
 
+bool rna_Object_constraints_override_apply(
+        PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *UNUSED(ptr_storage),
+        PropertyRNA *UNUSED(prop_dst), PropertyRNA *UNUSED(prop_src), PropertyRNA *UNUSED(prop_storage),
+        const int UNUSED(len_dst), const int UNUSED(len_src), const int UNUSED(len_storage),
+        IDOverrideStaticPropertyOperation *opop)
+{
+       BLI_assert(opop->operation == IDOVERRIDESTATIC_OP_INSERT_AFTER &&
+                  "Unsupported RNA override operation on constraints collection");
+
+       Object *ob_dst = (Object *)ptr_dst->id.data;
+       Object *ob_src = (Object *)ptr_src->id.data;
+
+       /* Remember that insertion operations are defined and stored in correct order, which means that
+        * even if we insert several items in a row, we alays insert first one, then second one, etc.
+        * So we should always find 'anchor' constraint in both _src *and* _dst> */
+       bConstraint *con_anchor = NULL;
+       if (opop->subitem_local_name && opop->subitem_local_name[0]) {
+               con_anchor = BLI_findstring(&ob_dst->constraints, opop->subitem_local_name, offsetof(bConstraint, name));
+       }
+       if (con_anchor == NULL && opop->subitem_local_index >= 0) {
+               con_anchor = BLI_findlink(&ob_dst->constraints, opop->subitem_local_index);
+       }
+       /* Otherwise we just insert in first position. */
+
+       bConstraint *con_src = NULL;
+       if (opop->subitem_local_name && opop->subitem_local_name[0]) {
+               con_src = BLI_findstring(&ob_src->constraints, opop->subitem_local_name, offsetof(bConstraint, name));
+       }
+       if (con_src == NULL && opop->subitem_local_index >= 0) {
+               con_src = BLI_findlink(&ob_src->constraints, opop->subitem_local_index);
+       }
+       con_src = con_src ? con_src->next : ob_src->constraints.first;
+
+       BLI_assert(con_src != NULL);
+
+       bConstraint *con_dst = BKE_constraint_duplicate_ex(con_src, 0, true);
+
+       /* This handles NULL anchor as expected by adding at head of list. */
+       BLI_insertlinkafter(&ob_dst->constraints, con_anchor, con_dst);
+
+       /* This should actually *not* be needed in typical cases. However, if overridden source was edited,
+        * we *may* have some new conflicting names. */
+       BKE_constraint_unique_name(con_dst, &ob_dst->constraints);
+
+//     printf("%s: We inserted a constraint...\n", __func__);
+       return true;
+}
+
 static ModifierData *rna_Object_modifier_new(Object *object, bContext *C, ReportList *reports,
                                              const char *name, int type)
 {
@@ -1159,6 +1209,55 @@ static void rna_Object_modifier_clear(Object *object, bContext *C)
        WM_main_add_notifier(NC_OBJECT | ND_MODIFIER | NA_REMOVED, object);
 }
 
+bool rna_Object_modifiers_override_apply(
+        PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *UNUSED(ptr_storage),
+        PropertyRNA *UNUSED(prop_dst), PropertyRNA *UNUSED(prop_src), PropertyRNA *UNUSED(prop_storage),
+        const int UNUSED(len_dst), const int UNUSED(len_src), const int UNUSED(len_storage),
+        IDOverrideStaticPropertyOperation *opop)
+{
+       BLI_assert(opop->operation == IDOVERRIDESTATIC_OP_INSERT_AFTER &&
+                  "Unsupported RNA override operation on modifiers collection");
+
+       Object *ob_dst = (Object *)ptr_dst->id.data;
+       Object *ob_src = (Object *)ptr_src->id.data;
+
+       /* Remember that insertion operations are defined and stored in correct order, which means that
+        * even if we insert several items in a row, we alays insert first one, then second one, etc.
+        * So we should always find 'anchor' constraint in both _src *and* _dst> */
+       ModifierData *mod_anchor = NULL;
+       if (opop->subitem_local_name && opop->subitem_local_name[0]) {
+               mod_anchor = BLI_findstring(&ob_dst->modifiers, opop->subitem_local_name, offsetof(ModifierData, name));
+       }
+       if (mod_anchor == NULL && opop->subitem_local_index >= 0) {
+               mod_anchor = BLI_findlink(&ob_dst->modifiers, opop->subitem_local_index);
+       }
+       /* Otherwise we just insert in first position. */
+
+       ModifierData *mod_src = NULL;
+       if (opop->subitem_local_name && opop->subitem_local_name[0]) {
+               mod_src = BLI_findstring(&ob_src->modifiers, opop->subitem_local_name, offsetof(ModifierData, name));
+       }
+       if (mod_src == NULL && opop->subitem_local_index >= 0) {
+               mod_src = BLI_findlink(&ob_src->modifiers, opop->subitem_local_index);
+       }
+       mod_src = mod_src ? mod_src->next : ob_src->modifiers.first;
+
+       BLI_assert(mod_src != NULL);
+
+       ModifierData *mod_dst = modifier_new(mod_src->type);
+       modifier_copyData(mod_src, mod_dst);
+
+       /* This handles NULL anchor as expected by adding at head of list. */
+       BLI_insertlinkafter(&ob_dst->modifiers, mod_anchor, mod_dst);
+
+       /* This should actually *not* be needed in typical cases. However, if overridden source was edited,
+        * we *may* have some new conflicting names. */
+       modifier_unique_name(&ob_dst->modifiers, mod_dst);
+
+//     printf("%s: We inserted a modifier...\n", __func__);
+       return true;
+}
+
 static void rna_Object_boundbox_get(PointerRNA *ptr, float *values)
 {
        Object *ob = (Object *)ptr->id.data;
@@ -2067,14 +2166,16 @@ static void rna_def_object(BlenderRNA *brna)
        prop = RNA_def_property(srna, "modifiers", PROP_COLLECTION, PROP_NONE);
        RNA_def_property_struct_type(prop, "Modifier");
        RNA_def_property_ui_text(prop, "Modifiers", "Modifiers affecting the geometric data of the object");
-       RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+       RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Object_modifiers_override_apply");
+       RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC | PROP_OVERRIDABLE_STATIC_INSERTION);
        rna_def_object_modifiers(brna, prop);
 
        /* constraints */
        prop = RNA_def_property(srna, "constraints", PROP_COLLECTION, PROP_NONE);
        RNA_def_property_struct_type(prop, "Constraint");
-       RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+       RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC | PROP_OVERRIDABLE_STATIC_INSERTION);
        RNA_def_property_ui_text(prop, "Constraints", "Constraints affecting the transformation of the object");
+       RNA_def_property_override_funcs(prop, NULL, NULL, "rna_Object_constraints_override_apply");
 /*     RNA_def_property_collection_funcs(prop, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "constraints__add", "constraints__remove"); */
        rna_def_object_constraints(brna, prop);
 
index a2005dbb16130ff3e1851bda37b40bdc51adfb70..8acf0f755f814472e684e780a353dc971611a52f 100644 (file)
@@ -563,6 +563,54 @@ static void rna_PoseChannel_constraints_remove(ID *id, bPoseChannel *pchan, Repo
        }
 }
 
+bool rna_PoseChannel_constraints_override_apply(
+        PointerRNA *ptr_dst, PointerRNA *ptr_src, PointerRNA *UNUSED(ptr_storage),
+        PropertyRNA *UNUSED(prop_dst), PropertyRNA *UNUSED(prop_src), PropertyRNA *UNUSED(prop_storage),
+        const int UNUSED(len_dst), const int UNUSED(len_src), const int UNUSED(len_storage),
+        IDOverrideStaticPropertyOperation *opop)
+{
+       BLI_assert(opop->operation == IDOVERRIDESTATIC_OP_INSERT_AFTER &&
+                  "Unsupported RNA override operation on constraints collection");
+
+       bPoseChannel *pchan_dst = (bPoseChannel *)ptr_dst->data;
+       bPoseChannel *pchan_src = (bPoseChannel *)ptr_src->data;
+
+       /* Remember that insertion operations are defined and stored in correct order, which means that
+        * even if we insert several items in a row, we alays insert first one, then second one, etc.
+        * So we should always find 'anchor' constraint in both _src *and* _dst> */
+       bConstraint *con_anchor = NULL;
+       if (opop->subitem_local_name && opop->subitem_local_name[0]) {
+               con_anchor = BLI_findstring(&pchan_dst->constraints, opop->subitem_local_name, offsetof(bConstraint, name));
+       }
+       if (con_anchor == NULL && opop->subitem_local_index >= 0) {
+               con_anchor = BLI_findlink(&pchan_dst->constraints, opop->subitem_local_index);
+       }
+       /* Otherwise we just insert in first position. */
+
+       bConstraint *con_src = NULL;
+       if (opop->subitem_local_name && opop->subitem_local_name[0]) {
+               con_src = BLI_findstring(&pchan_src->constraints, opop->subitem_local_name, offsetof(bConstraint, name));
+       }
+       if (con_src == NULL && opop->subitem_local_index >= 0) {
+               con_src = BLI_findlink(&pchan_src->constraints, opop->subitem_local_index);
+       }
+       con_src = con_src ? con_src->next : pchan_src->constraints.first;
+
+       BLI_assert(con_src != NULL);
+
+       bConstraint *con_dst = BKE_constraint_duplicate_ex(con_src, 0, true);
+
+       /* This handles NULL anchor as expected by adding at head of list. */
+       BLI_insertlinkafter(&pchan_dst->constraints, con_anchor, con_dst);
+
+       /* This should actually *not* be needed in typical cases. However, if overridden source was edited,
+        * we *may* have some new conflicting names. */
+       BKE_constraint_unique_name(con_dst, &pchan_dst->constraints);
+
+//     printf("%s: We inserted a constraint...\n", __func__);
+       return true;
+}
+
 static int rna_PoseChannel_proxy_editable(PointerRNA *ptr, const char **r_info)
 {
        Object *ob = (Object *)ptr->id.data;
@@ -806,8 +854,9 @@ static void rna_def_pose_channel(BlenderRNA *brna)
        /* Bone Constraints */
        prop = RNA_def_property(srna, "constraints", PROP_COLLECTION, PROP_NONE);
        RNA_def_property_struct_type(prop, "Constraint");
-       RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC);
+       RNA_def_property_flag(prop, PROP_OVERRIDABLE_STATIC | PROP_OVERRIDABLE_STATIC_INSERTION);
        RNA_def_property_ui_text(prop, "Constraints", "Constraints that act on this PoseChannel");
+       RNA_def_property_override_funcs(prop, NULL, NULL, "rna_PoseChannel_constraints_override_apply");
 
        rna_def_pose_channel_constraints(brna, prop);
 
index 448d0882fb3bf39d454c68a1e14812b4cc7edffc..8cd0f94f54666307d84e7f11f46009330e49629f 100644 (file)
@@ -106,6 +106,7 @@ const EnumPropertyItem rna_enum_property_unit_items[] = {
 #ifdef RNA_RUNTIME
 #include "MEM_guardedalloc.h"
 #include "BLI_ghash.h"
+#include "BLI_string.h"
 
 #include "BKE_library_override.h"
 
@@ -1093,39 +1094,129 @@ static int rna_BlenderRNA_structs_lookup_string(PointerRNA *ptr, const char *key
 
 /* Default override (and compare) callbacks. */
 
-/* Used for both Pointer and Collection properties. */
-static int rna_property_override_diff_propptr(
-        PointerRNA *propptr_a, PointerRNA *propptr_b, eRNACompareMode mode, const bool no_ownership,
-        IDOverrideStatic *override, const char *rna_path, const int flags, bool *r_override_changed)
+/* Ensures it makes sense to go inside the pointers to compare their content
+ * (if they are IDs, or have different names or RNA type, then this would be meaningless). */
+static bool rna_property_override_diff_propptr_validate_diffing(
+        PointerRNA *propptr_a, PointerRNA *propptr_b,
+        bool *r_is_id, bool *r_is_null, bool *r_is_type_diff,
+        char **r_propname_a, char *propname_a_buff, size_t propname_a_buff_size,
+        char **r_propname_b, char *propname_b_buff, size_t propname_b_buff_size)
 {
-       const bool do_create = override != NULL && (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0 && rna_path != NULL;
+       BLI_assert(propptr_a != NULL);
 
-       bool is_id = false;
-       bool is_type_null = false;
+       bool is_valid_for_diffing = true;
+       const bool do_force_name = r_propname_a != NULL;
+
+       if (do_force_name) {
+               BLI_assert(r_propname_a != NULL);
+               BLI_assert(r_propname_b != NULL);
+       }
+
+       *r_is_id = *r_is_null = *r_is_type_diff = false;
 
        /* Beware, PointerRNA_NULL has no type and is considered a 'blank page'! */
        if (propptr_a->type == NULL) {
-               if (propptr_b->type == NULL) {
-                       if (r_override_changed) {
-                               *r_override_changed = false;
-                       }
-                       return 0;
+               if (propptr_b == NULL || propptr_b->type == NULL) {
+                       *r_is_null = true;
                }
-               is_id = RNA_struct_is_ID(propptr_b->type);
-               is_type_null = true;
+               else {
+                       *r_is_id = RNA_struct_is_ID(propptr_b->type);
+                       *r_is_null = true;
+                       *r_is_type_diff = true;
+               }
+               is_valid_for_diffing = false;
        }
        else {
-               is_id = RNA_struct_is_ID(propptr_a->type);
-               is_type_null = (propptr_b->type == NULL);
+               *r_is_id = RNA_struct_is_ID(propptr_a->type);
+               *r_is_null = *r_is_type_diff = (ELEM(NULL, propptr_b, propptr_b->type));
+               is_valid_for_diffing = !(*r_is_id || *r_is_null);
        }
 
-       if (is_id) {
+       if (propptr_b == NULL || propptr_a->type != propptr_b->type) {
+               *r_is_type_diff = true;
+               is_valid_for_diffing = false;
+//             printf("%s: different pointer RNA types\n", rna_path ? rna_path : "<UNKNOWN>");
+       }
+
+       /* We do a generic quick first comparison checking for "name" and/or "type" properties.
+        * We assume that is any of those are false, then we are not handling the same data.
+        * This helps a lot in static override case, especially to detect inserted items in collections. */
+       if (is_valid_for_diffing || do_force_name) {
+               PropertyRNA *nameprop_a = RNA_struct_name_property(propptr_a->type);
+               PropertyRNA *nameprop_b = (propptr_b != NULL) ? RNA_struct_name_property(propptr_b->type) : NULL;
+
+               int propname_a_len = 0, propname_b_len = 0;
+               char *propname_a = NULL;
+               char *propname_b = NULL;
+               char buff_a[4096];
+               char buff_b[4096];
+               if (nameprop_a != NULL) {
+                       if (r_propname_a == NULL && propname_a_buff == NULL) {
+                               propname_a_buff = buff_a;
+                               propname_a_buff_size = sizeof(buff_a);
+                       }
+
+                       propname_a = RNA_property_string_get_alloc(
+                                        propptr_a, nameprop_a, propname_a_buff, propname_a_buff_size, &propname_a_len);
+//                     printf("propname_a = %s\n", propname_a ? propname_a : "<NONE>");
+
+                       if (r_propname_a != NULL) {
+                               *r_propname_a = propname_a;
+                       }
+               }
+//             else printf("item of type %s a has no name property!\n", propptr_a->type->name);
+               if (nameprop_b != NULL) {
+                       if (r_propname_b == NULL && propname_b_buff == NULL) {
+                               propname_b_buff = buff_b;
+                               propname_b_buff_size = sizeof(buff_b);
+                       }
+
+                       propname_b = RNA_property_string_get_alloc(
+                                        propptr_b, nameprop_b, propname_b_buff, propname_b_buff_size, &propname_b_len);
+
+                       if (r_propname_b != NULL) {
+                               *r_propname_b = propname_b;
+                       }
+               }
+               if (propname_a != NULL && propname_b != NULL) {
+                       if (propname_a_len != propname_b_len ||
+                           propname_a[0] != propname_b[0] ||
+                           !STREQ(propname_a, propname_b))
+                       {
+                               is_valid_for_diffing = false;
+//                             printf("%s: different names\n", rna_path ? rna_path : "<UNKNOWN>");
+                       }
+               }
+       }
+
+       if (*r_is_id) {
                BLI_assert(propptr_a->data == propptr_a->id.data && propptr_b->data == propptr_b->id.data);
+       }
+
+       return is_valid_for_diffing;
+}
+
+/* Used for both Pointer and Collection properties. */
+static int rna_property_override_diff_propptr(
+        PointerRNA *propptr_a, PointerRNA *propptr_b, eRNACompareMode mode, const bool no_ownership,
+        IDOverrideStatic *override, const char *rna_path, const int flags, bool *r_override_changed)
+{
+       const bool do_create = override != NULL && (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0 && rna_path != NULL;
+
+       bool is_id = false;
+       bool is_null = false;
+       bool is_type_diff = false;
+       /* If false, it means that the whole data itself is different, so no point in going inside of it at all! */
+       bool is_valid_for_diffing = rna_property_override_diff_propptr_validate_diffing(
+                                       propptr_a, propptr_b, &is_id, &is_null, &is_type_diff,
+                                       NULL, NULL, 0, NULL, NULL, 0);
+
+       if (is_id) {
                BLI_assert(no_ownership);  /* For now, once we deal with nodetrees we'll want to get rid of that one. */
        }
 
        if (override) {
-               if (no_ownership /* || is_id */ || is_type_null) {
+               if (no_ownership /* || is_id */ || is_null || is_type_diff || !is_valid_for_diffing) {
                        /* In case this pointer prop does not own its data (or one is NULL), do not compare structs!
                         * This is a quite safe path to infinite loop, among other nasty issues.
                         * Instead, just compare pointers themselves. */
@@ -1156,6 +1247,8 @@ static int rna_property_override_diff_propptr(
                }
        }
        else {
+               /* We could also use is_diff_pointer, but then we potentially lose the gt/lt info -
+                * and don't think performances are critical here for now anyway... */
                return !RNA_struct_equals(propptr_a, propptr_b, mode);
        }
 }
@@ -1374,10 +1467,13 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
 
                case PROP_STRING:
                {
-                       char fixed_a[128], fixed_b[128];
+                       char fixed_a[4096], fixed_b[4096];
                        int len_str_a, len_str_b;
                        char *value_a = RNA_property_string_get_alloc(ptr_a, prop_a, fixed_a, sizeof(fixed_a), &len_str_a);
                        char *value_b = RNA_property_string_get_alloc(ptr_b, prop_b, fixed_b, sizeof(fixed_b), &len_str_b);
+                       /* TODO we could do a check on length too, but then we would not have a 'real' string comparison...
+                        * Maybe behind a eRNAOverrideMatch flag? */
+//                     const int comp = len_str_a < len_str_b ? -1 : len_str_a > len_str_b ? 1 : strcmp(value_a, value_b);
                        const int comp = strcmp(value_a, value_b);
 
                        if (do_create && comp != 0) {
@@ -1418,85 +1514,194 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
 
                case PROP_COLLECTION:
                {
+                       /* Note: we assume we only insert in ptr_a (i.e. we can only get new items in ptr_a),
+                        * and that we never remove anything. */
+                       const bool use_insertion = (RNA_property_flag(prop_a) & PROP_OVERRIDABLE_STATIC_INSERTION) && do_create;
                        bool equals = true;
-                       int idx = 0;
+                       bool abort = false;
+                       bool is_first_insert = true;
+                       int idx_a = 0;
+                       int idx_b = 0;
+
+#define RNA_PATH_BUFFSIZE 8192
+
+                       char extended_rna_path_buffer[RNA_PATH_BUFFSIZE];
+                       char *extended_rna_path = extended_rna_path_buffer;
+
+#define RNA_PATH_PRINTF(_str, ...) \
+                       if (BLI_snprintf(extended_rna_path_buffer, RNA_PATH_BUFFSIZE, \
+                                        (_str), __VA_ARGS__) >= RNA_PATH_BUFFSIZE - 1) \
+                       { extended_rna_path = BLI_sprintfN((_str), __VA_ARGS__); }(void)0
+#define RNA_PATH_FREE() \
+                       if (extended_rna_path != extended_rna_path_buffer) MEM_freeN(extended_rna_path)
 
                        CollectionPropertyIterator iter_a, iter_b;
                        RNA_property_collection_begin(ptr_a, prop_a, &iter_a);
                        RNA_property_collection_begin(ptr_b, prop_b, &iter_b);
 
-                       for (; iter_a.valid && iter_b.valid;
-                            RNA_property_collection_next(&iter_a), RNA_property_collection_next(&iter_b), idx++)
-                       {
-                               if (iter_a.ptr.type != iter_b.ptr.type) {
-                                       /* nothing we can do (for until we support adding/removing from collections), skip it. */
-                                       equals = false;
-                                       continue;
-                               }
-                               else if (iter_a.ptr.type == NULL) {
-                                       /* NULL RNA pointer... */
-                                       BLI_assert(iter_a.ptr.data == NULL);
-                                       BLI_assert(iter_b.ptr.data == NULL);
-                                       continue;
-                               }
+                       char buff_a[4096];
+                       char buff_prev_a[4096] = {0};
+                       char buff_b[4096];
+                       char *propname_a = NULL;
+                       char *prev_propname_a = buff_prev_a;
+                       char *propname_b = NULL;
+
+                       for (; iter_a.valid && !abort; ) {
+                               bool is_valid_for_diffing;
+                               bool is_valid_for_insertion;
+                               do {
+                                       bool is_id = false, is_null = false, is_type_diff = false;
+
+                                       is_valid_for_insertion = use_insertion;
+
+                                       /* If false, it means that the whole data itself is different, so no point in going inside of it at all! */
+                                       if (iter_b.valid) {
+                                               is_valid_for_diffing = rna_property_override_diff_propptr_validate_diffing(
+                                                                               &iter_a.ptr, &iter_b.ptr, &is_id, &is_null, &is_type_diff,
+                                                                               &propname_a, buff_a, sizeof(buff_a),
+                                                                               &propname_b, buff_b, sizeof(buff_b));
+                                       }
+                                       else {
+                                               is_valid_for_diffing = false;
+                                               if (is_valid_for_insertion) {
+                                                       /* We still need propname from 'a' item... */
+                                                       rna_property_override_diff_propptr_validate_diffing(
+                                                                   &iter_a.ptr, NULL, &is_id, &is_null, &is_type_diff,
+                                                                   &propname_a, buff_a, sizeof(buff_a),
+                                                                   &propname_b, buff_b, sizeof(buff_b));
+                                               }
+                                       }
 
-                               PropertyRNA *propname = RNA_struct_name_property(iter_a.ptr.type);
-                               char propname_buff_a[256], propname_buff_b[256];
-                               char *propname_a = NULL, *propname_b = NULL;
+                                       /* We do not support insertion of IDs for now, neither handle NULL pointers. */
+                                       if (is_id || is_valid_for_diffing) {
+                                               is_valid_for_insertion = false;
+                                       }
 
-                               if (propname != NULL) {
-                                       propname_a = RNA_property_string_get_alloc(&iter_a.ptr, propname, propname_buff_a, sizeof(propname_buff_a), NULL);
-                                       propname_b = RNA_property_string_get_alloc(&iter_b.ptr, propname, propname_buff_b, sizeof(propname_buff_b), NULL);
-                               }
+#if 0
+                                       if (rna_path) {
+                                               printf("Checking %s, %s [%d] vs %s [%d]; diffing: %d; insert: %d (could be used: %d, do_create: %d)\n",
+                                                      rna_path, propname_a ? propname_a : "", idx_a, propname_b ? propname_b : "", idx_b,
+                                                      is_valid_for_diffing, is_valid_for_insertion,
+                                                      (RNA_property_flag(prop_a) & PROP_OVERRIDABLE_STATIC_INSERTION) != 0, do_create);
+                                       }
+#endif
 
-#define RNA_PATH_BUFFSIZE 8192
-#define RNA_PATH_PRINTF(_str, ...) \
-                               if (BLI_snprintf(extended_rna_path_buffer, RNA_PATH_BUFFSIZE, \
-                                                (_str), __VA_ARGS__) >= RNA_PATH_BUFFSIZE) \
-                               { extended_rna_path = BLI_sprintfN((_str), __VA_ARGS__); }(void)0
-#define RNA_PATH_FREE \
-                               if (extended_rna_path != extended_rna_path_buffer) MEM_freeN(extended_rna_path)
-
-                               char extended_rna_path_buffer[RNA_PATH_BUFFSIZE];
-                               char *extended_rna_path = extended_rna_path_buffer;
-
-                               /* There may be a propname defined in some cases, while no actual name set
-                                * (e.g. happens with point cache), in that case too we want to fall back to index. */
-                               if ((propname_a != NULL && propname_a[0] != '\0') || (propname_b != NULL && propname_b[0] != '\0')) {
-                                       if (!STREQ(propname_a, propname_b)) {
-                                               /* Same as above, not same structs. */
+                                       if (!(is_valid_for_diffing || is_valid_for_insertion)) {
+                                               /* Differences we cannot handle, we can break here
+                                                * (we do not support replacing ID pointers in collections e.g.). */
                                                equals = false;
+                                               abort = true;
+                                               break;
                                        }
-                                       else if (rna_path) {
-                                               char esc_item_name[RNA_PATH_BUFFSIZE];
-                                               BLI_strescape(esc_item_name, propname_a, RNA_PATH_BUFFSIZE);
-                                               RNA_PATH_PRINTF("%s[\"%s\"]", rna_path, esc_item_name);
+
+                                       /* There may be a propname defined in some cases, while no actual name set
+                                        * (e.g. happens with point cache), in that case too we want to fall back to index.
+                                        * Note that we do not need the RNA path for insertion operations. */
+                                       if (is_valid_for_diffing) {
+                                               if ((propname_a != NULL && propname_a[0] != '\0') &&
+                                                   (propname_b != NULL && propname_b[0] != '\0'))
+                                               {
+                                                       if (rna_path) {
+                                                               /* In case of name, either it is valid for diffing, and _a and _b are identical,
+                                                                * or it is valid for insertion, and we need to use _a. */
+                                                               char esc_item_name[RNA_PATH_BUFFSIZE];
+                                                               BLI_strescape(esc_item_name, propname_a, RNA_PATH_BUFFSIZE);
+                                                               RNA_PATH_PRINTF("%s[\"%s\"]", rna_path, esc_item_name);
+                                                       }
+                                               }
+                                               else {  /* Based on index... */
+                                                       if (rna_path) {
+                                                               /* In case of indices, we need _a one for insertion, but _b ones for in-depth diffing.
+                                                                * Insertion always happen once all 'replace' operations have been done,
+                                                                * otherwise local and reference paths for those would have to be different! */
+                                                               RNA_PATH_PRINTF("%s[%d]", rna_path, is_valid_for_insertion ? idx_a : idx_b);
+                                                       }
+                                               }
                                        }
-                               }
-                               else {  /* Based on index... */
-                                       if (rna_path) {
-                                               RNA_PATH_PRINTF("%s[%d]", rna_path, idx);
+
+                                       /* Collections do not support replacement of their data (since they do not support removing),
+                                        * only in *some* cases, insertion.
+                                        * We also assume then that _a data is the one where things are inserted. */
+                                       if (is_valid_for_insertion && use_insertion) {
+                                               bool created;
+                                               IDOverrideStaticProperty *op = BKE_override_static_property_get(override, rna_path, &created);
+
+                                               if (is_first_insert) {
+                                                       /* We need to clean up all possible existing insertion operations, otherwise we'd end up
+                                                        * with a mess of ops everytime something changes. */
+                                                       for (IDOverrideStaticPropertyOperation *opop = op->operations.first;
+                                                            opop != NULL;)
+                                                       {
+                                                               IDOverrideStaticPropertyOperation *opop_next = opop->next;
+                                                               if (ELEM(opop->operation,
+                                                                        IDOVERRIDESTATIC_OP_INSERT_AFTER, IDOVERRIDESTATIC_OP_INSERT_BEFORE))
+                                                               {
+                                                                       BKE_override_static_property_operation_delete(op, opop);
+                                                               }
+                                                               opop = opop_next;
+                                                       }
+                                                       is_first_insert = false;
+                                               }
+
+                                               BKE_override_static_property_operation_get(
+                                                           op, IDOVERRIDESTATIC_OP_INSERT_AFTER,
+                                                           NULL, prev_propname_a, -1, idx_a - 1, true, NULL, NULL);
+//                                             printf("%s: Adding insertion op override after '%s'/%d\n", rna_path, prev_propname_a, idx_a - 1);
+                                       }
+                                       else if (is_valid_for_diffing) {
+                                               if (equals || do_create) {
+                                                       const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0;
+                                                       const int eq = rna_property_override_diff_propptr(
+                                                                     &iter_a.ptr, &iter_b.ptr, mode, no_ownership,
+                                                                     override, extended_rna_path, flags, r_override_changed);
+                                                       equals = equals && eq;
+                                               }
                                        }
-                               }
 
-                               if (equals || do_create) {
-                                       const bool no_ownership = (RNA_property_flag(prop_a) & PROP_PTR_NO_OWNERSHIP) != 0;
-                                       const int eq = rna_property_override_diff_propptr(
-                                                     &iter_a.ptr, &iter_b.ptr, mode, no_ownership,
-                                                     override, extended_rna_path, flags, r_override_changed);
-                                       equals = equals && eq;
-                               }
+                                       if (prev_propname_a != buff_prev_a) {
+                                               MEM_freeN(prev_propname_a);
+                                               prev_propname_a = buff_prev_a;
+                                       }
+                                       prev_propname_a[0] = '\0';
+                                       if (propname_a != NULL &&
+                                           BLI_strncpy_rlen(prev_propname_a, propname_a, sizeof(buff_prev_a)) >= sizeof(buff_prev_a) - 1)
+                                       {
+                                               prev_propname_a = BLI_strdup(propname_a);
+                                       }
+                                       if (propname_a != buff_a) {
+                                               MEM_SAFE_FREE(propname_a);
+                                               propname_a = buff_a;
+                                       }
+                                       propname_a[0] = '\0';
+                                       if (propname_b != buff_b) {
+                                               MEM_SAFE_FREE(propname_b);
+                                               propname_b = buff_b;
+                                       }
+                                       propname_b[0] = '\0';
+                                       RNA_PATH_FREE();
 
-                               if (propname_a != propname_buff_a) {
-                                       MEM_SAFE_FREE(propname_a);
-                               }
-                               if (propname_b != propname_buff_b) {
-                                       MEM_SAFE_FREE(propname_b);
-                               }
-                               RNA_PATH_FREE;
+                                       if (!do_create && !equals) {
+                                               abort = true;  /* Early out in case we do not want to loop over whole collection. */
+                                               break;
+                                       }
+
+                                       if (!(use_insertion && !is_valid_for_diffing)) {
+                                               break;
+                                       }
+
+                                       if (iter_a.valid) {
+                                               RNA_property_collection_next(&iter_a);
+                                               idx_a++;
+                                       }
+                               } while (iter_a.valid);
 
-                               if (!rna_path && !equals) {
-                                       break;  /* Early out in case we do not want to loop over whole collection. */
+                               if (iter_a.valid) {
+                                       RNA_property_collection_next(&iter_a);
+                                       idx_a++;
+                               }
+                               if (iter_b.valid) {
+                                       RNA_property_collection_next(&iter_b);
+                                       idx_b++;
                                }
 
 #undef RNA_PATH_BUFFSIZE
@@ -1504,7 +1709,7 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b,
 #undef RNA_PATH_FREE
                        }
 
-                       equals = equals && !(iter_a.valid || iter_b.valid);  /* Not same number of items in both collections... */
+                       equals = equals && !(iter_a.valid || iter_b.valid) && !abort;  /* Not same number of items in both collections... */
                        RNA_property_collection_end(&iter_a);
                        RNA_property_collection_end(&iter_b);
 
@@ -2096,8 +2301,13 @@ bool rna_property_override_apply_default(
                        if (value != buff) MEM_freeN(value);
                        return true;
                }
+               case PROP_COLLECTION:
+               {
+                       BLI_assert(!"You need to define a specific override apply callback for enums.");
+                       return false;
+               }
                default:
-                       /* TODO PROP_COLLECTION of course! */
+                       BLI_assert(0);
                        return false;
        }