== Massive Keying Sets Recode ==
authorJoshua Leung <aligorith@gmail.com>
Tue, 16 Mar 2010 06:18:49 +0000 (06:18 +0000)
committerJoshua Leung <aligorith@gmail.com>
Tue, 16 Mar 2010 06:18:49 +0000 (06:18 +0000)
After a few days of wrong turns and learning the finer points of RNA-type-subclassing the hard way, this commit finally presents a refactored version of the Keying Sets system (now version 2) based on some requirements from Cessen.

For a more thorough discussion of this commit, see
http://sites.google.com/site/aligorith/keyingsets_2.pdf?attredirects=0&d=1

------

The main highlight of this refactor is that relative Keying Sets have now been recoded so that Python callbacks are run to generate the Keying Set's list of paths everytime the Keying Set is used (to insert or delete keyframes), allowing complex heuristics to be used to determine whether a property gets keyframed based on the current context. These checks may include checking on selection status of related entities, or transform locks.

Built-In KeyingSets have also been recoded, and moved from C and out into Python. These are now coded as Relative Keying Sets, and can to some extent serve as basis for adding new relative Keying Sets. However, these have mostly been coded in a slightly 'modular' way which may be confusing for those not so familiar with Python in general. A usable template will be added soon for more general usage.

Keyframing settings (i.e. 'visual', 'needed') can now be specified on a per-path basis now, which is especially useful for Absolute Keying Sets, where control over this is often beneficial.

Most of the places where Auto-Keyframing is performed have been tidied up for consistency. I'm sure quite a few issues still exist there, but these I'll clean up over the next few days.

21 files changed:
release/scripts/keyingsets/keyingsets_builtins.py [new file with mode: 0644]
release/scripts/keyingsets/keyingsets_utils.py [new file with mode: 0644]
release/scripts/modules/bpy/utils.py
source/blender/blenkernel/BKE_animsys.h
source/blender/blenkernel/intern/anim_sys.c
source/blender/editors/animation/anim_intern.h
source/blender/editors/animation/keyframing.c
source/blender/editors/animation/keyingsets.c
source/blender/editors/armature/editarmature.c
source/blender/editors/armature/poseUtils.c
source/blender/editors/armature/poselib.c
source/blender/editors/armature/poseobject.c
source/blender/editors/include/ED_keyframing.h
source/blender/editors/object/object_transform.c
source/blender/editors/space_view3d/view3d_view.c
source/blender/editors/transform/transform_conversions.c
source/blender/makesdna/DNA_anim_types.h
source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/rna_animation.c
source/blender/makesrna/intern/rna_animation_api.c
source/blender/windowmanager/intern/wm_init_exit.c

diff --git a/release/scripts/keyingsets/keyingsets_builtins.py b/release/scripts/keyingsets/keyingsets_builtins.py
new file mode 100644 (file)
index 0000000..c5417ba
--- /dev/null
@@ -0,0 +1,236 @@
+# Built-In Keying Sets
+# None of these Keying Sets should be removed, as these
+# are needed by various parts of Blender in order for them
+# to work correctly.
+
+import bpy
+from keyingsets_utils import *
+
+###############################
+# Built-In KeyingSets
+
+# Location
+class BUILTIN_KSI_Location(bpy.types.KeyingSetInfo):
+       bl_idname = "Location"
+       bl_builtin = True
+       
+       # poll - use predefined callback for selected bones/objects
+       poll = RKS_POLL_selected_items
+       
+       # iterator - use callback for selected bones/objects
+       iterator = RKS_ITER_selected_item
+       
+       # generator - use callback for location 
+       generate = RKS_GEN_location
+       
+# Rotation
+class BUILTIN_KSI_Rotation(bpy.types.KeyingSetInfo):
+       bl_idname = "Rotation"
+       bl_builtin = True
+       
+       # poll - use predefined callback for selected bones/objects
+       poll = RKS_POLL_selected_items
+       
+       # iterator - use callback for selected bones/objects
+       iterator = RKS_ITER_selected_item
+       
+       # generator - use callback for location 
+       generate = RKS_GEN_rotation
+       
+# Scale
+class BUILTIN_KSI_Scaling(bpy.types.KeyingSetInfo):
+       bl_idname = "Scaling"
+       bl_builtin = True
+       
+       # poll - use predefined callback for selected bones/objects
+       poll = RKS_POLL_selected_items
+       
+       # iterator - use callback for selected bones/objects
+       iterator = RKS_ITER_selected_item
+       
+       # generator - use callback for location 
+       generate = RKS_GEN_scaling
+
+# ------------
+       
+# LocRot
+class BUILTIN_KSI_LocRot(bpy.types.KeyingSetInfo):
+       bl_idname = "LocRot"
+       bl_builtin = True
+       
+       # poll - use predefined callback for selected bones/objects
+       poll = RKS_POLL_selected_items
+       
+       # iterator - use callback for selected bones/objects
+       iterator = RKS_ITER_selected_item
+       
+       # generator - use callback for location 
+       def generate(self, context, ks, data):
+               # location
+               RKS_GEN_location(self, context, ks, data)
+               # rotation
+               RKS_GEN_rotation(self, context, ks, data)
+
+# LocScale
+class BUILTIN_KSI_LocScale(bpy.types.KeyingSetInfo):
+       bl_idname = "LocScale"
+       bl_builtin = True
+       
+       # poll - use predefined callback for selected bones/objects
+       poll = RKS_POLL_selected_items
+       
+       # iterator - use callback for selected bones/objects
+       iterator = RKS_ITER_selected_item
+       
+       # generator - use callback for location 
+       def generate(self, context, ks, data):
+               # location
+               RKS_GEN_location(self, context, ks, data)
+               # scale
+               RKS_GEN_scaling(self, context, ks, data)
+
+# LocRotScale
+class BUILTIN_KSI_LocRotScale(bpy.types.KeyingSetInfo):
+       bl_idname = "LocRotScale"
+       bl_builtin = True
+       
+       # poll - use predefined callback for selected bones/objects
+       poll = RKS_POLL_selected_items
+       
+       # iterator - use callback for selected bones/objects
+       iterator = RKS_ITER_selected_item
+       
+       # generator - use callback for location 
+       def generate(self, context, ks, data):
+               # location
+               RKS_GEN_location(self, context, ks, data)
+               # rotation
+               RKS_GEN_rotation(self, context, ks, data)
+               # scale
+               RKS_GEN_scaling(self, context, ks, data)
+
+# RotScale
+class BUILTIN_KSI_RotScale(bpy.types.KeyingSetInfo):
+       bl_idname = "RotScale"
+       bl_builtin = True
+       
+       # poll - use predefined callback for selected bones/objects
+       poll = RKS_POLL_selected_items
+       
+       # iterator - use callback for selected bones/objects
+       iterator = RKS_ITER_selected_item
+       
+       # generator - use callback for location 
+       def generate(self, context, ks, data):
+               # rotation
+               RKS_GEN_rotation(self, context, ks, data)
+               # scaling
+               RKS_GEN_scaling(self, context, ks, data)
+               
+# ------------
+
+# Location
+class BUILTIN_KSI_VisualLoc(bpy.types.KeyingSetInfo):
+       bl_idname = "Visual Location"
+       bl_builtin = True
+       
+       insertkey_visual = True
+       
+       # poll - use predefined callback for selected bones/objects
+       poll = RKS_POLL_selected_items
+       
+       # iterator - use callback for selected bones/objects
+       iterator = RKS_ITER_selected_item
+       
+       # generator - use callback for location 
+       generate = RKS_GEN_location
+       
+# Rotation
+class BUILTIN_KSI_VisualRot(bpy.types.KeyingSetInfo):
+       bl_idname = "Visual Rotation"
+       bl_builtin = True
+       
+       insertkey_visual = True
+       
+       # poll - use predefined callback for selected bones/objects
+       poll = RKS_POLL_selected_items
+       
+       # iterator - use callback for selected bones/objects
+       iterator = RKS_ITER_selected_item
+       
+       # generator - use callback for location 
+       generate = RKS_GEN_rotation
+
+# VisualLocRot
+class BUILTIN_KSI_VisualLocRot(bpy.types.KeyingSetInfo):
+       bl_idname = "Visual LocRot"
+       bl_builtin = True
+       
+       insertkey_visual = True
+       
+       # poll - use predefined callback for selected bones/objects
+       poll = RKS_POLL_selected_items
+       
+       # iterator - use callback for selected bones/objects
+       iterator = RKS_ITER_selected_item
+       
+       # generator - use callback for location 
+       def generate(self, context, ks, data):
+               # location
+               RKS_GEN_location(self, context, ks, data)
+               # rotation
+               RKS_GEN_rotation(self, context, ks, data)
+
+# ------------
+
+# Available
+class BUILTIN_KSI_Available(bpy.types.KeyingSetInfo):
+       bl_idname = "Available"
+       bl_builtin = True
+       
+       # poll - use predefined callback for selected objects
+       # TODO: this should really check whether the selected object (or datablock) 
+       #               has any animation data defined yet
+       poll = RKS_POLL_selected_objects
+       
+       # iterator - use callback for selected bones/objects
+       iterator = RKS_ITER_selected_item
+       
+       # generator - use callback for location 
+       generate = RKS_GEN_available
+
+############################### 
+
+classes = [
+       BUILTIN_KSI_Location,
+       BUILTIN_KSI_Rotation,
+       BUILTIN_KSI_Scaling,
+       
+       BUILTIN_KSI_LocRot,
+       BUILTIN_KSI_LocScale,
+       BUILTIN_KSI_LocRotScale,
+       BUILTIN_KSI_RotScale,
+       
+       BUILTIN_KSI_VisualLoc,
+       BUILTIN_KSI_VisualRot,
+       BUILTIN_KSI_VisualLocRot,
+       
+       BUILTIN_KSI_Available,
+]
+
+
+def register():
+    register = bpy.types.register
+    for cls in classes:
+        register(cls)
+
+
+def unregister():
+    unregister = bpy.types.unregister
+    for cls in classes:
+        unregister(cls)
+
+if __name__ == "__main__":
+    register()
+
+############################### 
diff --git a/release/scripts/keyingsets/keyingsets_utils.py b/release/scripts/keyingsets/keyingsets_utils.py
new file mode 100644 (file)
index 0000000..78e170c
--- /dev/null
@@ -0,0 +1,170 @@
+# This file defines a set of methods that are useful for various 
+# Relative Keying Set (RKS) related operations, such as: callbacks
+# for polling, iterator callbacks, and also generate callbacks. 
+# All of these can be used in conjunction with the others. 
+
+import bpy
+
+###########################
+# General Utilities
+
+# Append the specified property name on the the existing path
+def path_add_property(path, prop):
+    if len(path):
+        return path + "." + prop;
+    else:
+        return prop;
+
+###########################
+# Poll Callbacks
+
+# selected objects
+def RKS_POLL_selected_objects(ksi, context):
+    return context.active_object or len(context.selected_objects);
+    
+# selected bones
+def RKS_POLL_selected_bones(ksi, context):
+    # we must be in Pose Mode, and there must be some bones selected 
+    if (context.active_object) and (context.active_object.mode == 'POSE'):
+        if context.active_pose_bone or len(context.select_pose_bones):
+            return True;
+    
+    # nothing selected 
+    return False;
+
+
+# selected bones or objects
+def RKS_POLL_selected_items(ksi, context):
+    return RKS_POLL_selected_bones(ksi, context) or RKS_POLL_selected_objects(ksi, context);
+
+###########################
+# Iterator Callbacks
+
+# all selected objects or pose bones, depending on which we've got
+def RKS_ITER_selected_item(ksi, context, ks):
+    if (context.active_object) and (context.active_object.mode == 'POSE'):
+        for bone in context.selected_pose_bones:
+            ksi.generate(context, ks, bone)
+    else:
+        for ob in context.selected_objects:
+            ksi.generate(context, ks, ob)
+
+###########################
+# Generate Callbacks
+
+# 'Available' F-Curves
+def RKS_GEN_available(ksi, context, ks, data):
+    # try to get the animation data associated with the closest 
+    # ID-block to the data (neither of which may exist/be easy to find)
+    id_block = data.id_data
+    try:
+        adt = id_block.animation_data
+    except:
+        # there isn't any animation data available 
+        return;
+        
+    # there must also be an active action...
+    if adt.action is None:
+        return;
+        
+    # for each F-Curve, include an path to key it
+    # NOTE: we don't need to set the group settings here
+    for fcu in adt.action.fcurves:
+        ks.add_path(id_block, fcu.rna_path, array_index=fcu.array_index, entire_array=False)
+    
+# ------
+
+# get ID block and based ID path for transform generators
+def get_transform_generators_base_info(data):
+    # ID-block for the data 
+    id_block = data.id_data
+    
+    # get base path and grouping method/name
+    if isinstance(data, bpy.types.ID):
+        # no path in this case
+        path = ""
+        
+        # data on ID-blocks directly should get grouped by the KeyingSet
+        grouping = None;
+    else:
+        # get the path to the ID-block
+        path = data.path_to_id()
+        
+        try:
+            # try to use the name of the data element to group the F-Curve
+            grouping = data.name
+        except:
+            # fallback on the KeyingSet name
+            grouping = None;
+        
+    # return the ID-block and the path
+    return id_block, path, grouping
+
+# Location 
+def RKS_GEN_location(ksi, context, ks, data):
+    # get id-block and path info
+    id_block, base_path, grouping= get_transform_generators_base_info(data)
+    
+    # add the property name to the base path
+    path = path_add_property(base_path, "location")
+    
+    # add Keying Set entry for this...
+    if grouping:
+        ks.add_path(id_block, path, grouping_method='NAMED', group_name=grouping)
+    else:
+        ks.add_path(id_block, path)
+
+# Rotation 
+def RKS_GEN_rotation(ksi, context, ks, data):
+    # get id-block and path info
+    id_block, base_path, grouping= get_transform_generators_base_info(data)
+    
+    # add the property name to the base path
+    #   rotation mode affects the property used
+    if data.rotation_mode == 'QUATERNION':
+        path = path_add_property(base_path, "rotation_quaternion")
+    elif data.rotation_mode == 'AXISANGLE':
+        path = path_add_property(base_path, "rotation_axis_angle")
+    else:
+        path = path_add_property(base_path, "rotation_euler")
+    
+    # add Keying Set entry for this...
+    if grouping:
+        ks.add_path(id_block, path, grouping_method='NAMED', group_name=grouping)
+    else:
+        ks.add_path(id_block, path)
+
+# Scaling 
+def RKS_GEN_scaling(ksi, context, ks, data):
+    # get id-block and path info
+    id_block, base_path, grouping= get_transform_generators_base_info(data)
+    
+    # add the property name to the base path
+    path = path_add_property(base_path, "scale")
+    
+    # add Keying Set entry for this...
+    if grouping:
+        ks.add_path(id_block, path, grouping_method='NAMED', group_name=grouping)
+    else:
+        ks.add_path(id_block, path)
+
+###########################
+# Un-needed stuff which is here to just shut up the warnings...
+
+classes = []
+
+def register():
+    register = bpy.types.register
+    for cls in classes:
+        register(cls)
+
+
+def unregister():
+    unregister = bpy.types.unregister
+    for cls in classes:
+        unregister(cls)
+
+if __name__ == "__main__":
+    register()
+
+###########################
index 7787d9ee5fe06e1452a4c674f015cd234103727f..5b0599fe25fcfd4137a8d420e0964f1ca3156505 100644 (file)
@@ -169,7 +169,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
         _loaded[:] = []
 
     for base_path in script_paths(user=False):
-        for path_subdir in ("ui", "op", "io", "cfg"):
+        for path_subdir in ("ui", "op", "io", "cfg", "keyingsets"):
             path = _os.path.join(base_path, path_subdir)
             if _os.path.isdir(path):
                 sys_path_ensure(path)
@@ -179,7 +179,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
 
     user_path = user_script_path()
     if user_path:
-        for path_subdir in ("", "ui", "op", "io", "cfg"):
+        for path_subdir in ("", "ui", "op", "io", "cfg", "keyingsets"):
             path = _os.path.join(user_path, path_subdir)
             if _os.path.isdir(path):
                 sys_path_ensure(path)
index f6950ba07b887ec05f26c1b8b683de9ea0dea29f..8644074d4e94dbfd5cf892d0d548fb5de5cf526a 100644 (file)
@@ -71,7 +71,7 @@ void BKE_animdata_make_local(struct AnimData *adt);
 struct KeyingSet *BKE_keyingset_add(struct ListBase *list, const char name[], short flag, short keyingflag);
 
 /* Add a path to a KeyingSet */
-void BKE_keyingset_add_path(struct KeyingSet *ks, struct ID *id, const char group_name[], const char rna_path[], int array_index, short flag, short groupmode);
+struct KS_Path *BKE_keyingset_add_path(struct KeyingSet *ks, struct ID *id, const char group_name[], const char rna_path[], int array_index, short flag, short groupmode);
 
 /* Find the destination matching the criteria given */
 struct KS_Path *BKE_keyingset_find_path(struct KeyingSet *ks, struct ID *id, const char group_name[], const char rna_path[], int array_index, int group_mode);
@@ -79,6 +79,9 @@ struct KS_Path *BKE_keyingset_find_path(struct KeyingSet *ks, struct ID *id, con
 /* Copy all KeyingSets in the given list */
 void BKE_keyingsets_copy(struct ListBase *newlist, struct ListBase *list);
 
+/* Free the given Keying Set path */
+void BKE_keyingset_free_path(struct KeyingSet *ks, struct KS_Path *ksp);
+
 /* Free data for KeyingSet but not set itself */
 void BKE_keyingset_free(struct KeyingSet *ks);
 
index a880417a11158509f5980cf922e342f32c9213a4..8ec8f24d5feb198fbfa84c918f990cc429934909 100644 (file)
@@ -621,53 +621,48 @@ KeyingSet *BKE_keyingset_add (ListBase *list, const char name[], short flag, sho
        return ks;
 }
 
-/* Add a destination to a KeyingSet. Nothing is returned for now...
+/* Add a path to a KeyingSet. Nothing is returned for now...
  * Checks are performed to ensure that destination is appropriate for the KeyingSet in question
  */
-void BKE_keyingset_add_path (KeyingSet *ks, ID *id, const char group_name[], const char rna_path[], int array_index, short flag, short groupmode)
+KS_Path *BKE_keyingset_add_path (KeyingSet *ks, ID *id, const char group_name[], const char rna_path[], int array_index, short flag, short groupmode)
 {
        KS_Path *ksp;
        
        /* sanity checks */
        if ELEM(NULL, ks, rna_path) {
-               printf("ERROR: no Keying Set and/or RNA Path to add destination with \n");
-               return;
+               printf("ERROR: no Keying Set and/or RNA Path to add path with \n");
+               return NULL;
        }
        
-       /* ID is optional for relative KeyingSets, but is necessary for absolute KeyingSets */
+       /* ID is required for all types of KeyingSets */
        if (id == NULL) {
-               if (ks->flag & KEYINGSET_ABSOLUTE) {
-                       printf("ERROR: No ID provided for absolute destination. \n");
-                       return;
-               }
+               printf("ERROR: No ID provided for Keying Set Path. \n");
+               return NULL;
        }
        
        /* don't add if there is already a matching KS_Path in the KeyingSet */
        if (BKE_keyingset_find_path(ks, id, group_name, rna_path, array_index, groupmode)) {
                if (G.f & G_DEBUG)
                        printf("ERROR: destination already exists in Keying Set \n");
-               return;
+               return NULL;
        }
        
        /* allocate a new KeyingSet Path */
        ksp= MEM_callocN(sizeof(KS_Path), "KeyingSet Path");
        
        /* just store absolute info */
-       if (ks->flag & KEYINGSET_ABSOLUTE) {
-               ksp->id= id;
-               if (group_name)
-                       BLI_snprintf(ksp->group, 64, group_name);
-               else
-                       strcpy(ksp->group, "");
-       }
+       ksp->id= id;
+       if (group_name)
+               BLI_snprintf(ksp->group, 64, group_name);
+       else
+               strcpy(ksp->group, "");
        
        /* store additional info for relative paths (just in case user makes the set relative) */
        if (id)
                ksp->idtype= GS(id->name);
        
        /* just copy path info */
-       // XXX no checks are performed for templates yet
-       // should array index be checked too?
+       // TODO: should array index be checked too?
        ksp->rna_path= BLI_strdupn(rna_path, strlen(rna_path));
        ksp->array_index= array_index;
        
@@ -677,20 +672,37 @@ void BKE_keyingset_add_path (KeyingSet *ks, ID *id, const char group_name[], con
        
        /* add KeyingSet path to KeyingSet */
        BLI_addtail(&ks->paths, ksp);
+       
+       /* return this path */
+       return ksp;
 }      
 
+/* Free the given Keying Set path */
+void BKE_keyingset_free_path (KeyingSet *ks, KS_Path *ksp)
+{
+       /* sanity check */
+       if ELEM(NULL, ks, ksp)
+               return;
+       
+       /* free RNA-path info */
+       MEM_freeN(ksp->rna_path);
+       
+       /* free path itself */
+       BLI_freelinkN(&ks->paths, ksp);
+}
+
 /* Copy all KeyingSets in the given list */
-void BKE_keyingsets_copy(ListBase *newlist, ListBase *list)
+void BKE_keyingsets_copy (ListBase *newlist, ListBase *list)
 {
        KeyingSet *ksn;
        KS_Path *kspn;
-
+       
        BLI_duplicatelist(newlist, list);
 
-       for(ksn=newlist->first; ksn; ksn=ksn->next) {
+       for (ksn=newlist->first; ksn; ksn=ksn->next) {
                BLI_duplicatelist(&ksn->paths, &ksn->paths);
-
-               for(kspn=ksn->paths.first; kspn; kspn=kspn->next)
+               
+               for (kspn=ksn->paths.first; kspn; kspn=kspn->next)
                        kspn->rna_path= MEM_dupallocN(kspn->rna_path);
        }
 }
@@ -709,12 +721,7 @@ void BKE_keyingset_free (KeyingSet *ks)
        /* free each path as we go to avoid looping twice */
        for (ksp= ks->paths.first; ksp; ksp= kspn) {
                kspn= ksp->next;
-               
-               /* free RNA-path info */
-               MEM_freeN(ksp->rna_path);
-               
-               /* free path itself */
-               BLI_freelinkN(&ks->paths, ksp);
+               BKE_keyingset_free_path(ks, ksp);
        }
 }
 
index 5602bff77ceceb20f9b2c53fbc97b031f5c96b1c..379b8c27de5453b14d4f943d0a21eb369c0e33b4 100644 (file)
 /* list of builtin KeyingSets (defined in keyingsets.c) */
 extern ListBase builtin_keyingsets;
 
-/* for builtin keyingsets - context poll */
-short keyingset_context_ok_poll(bContext *C, KeyingSet *ks);
-
-/* Main KeyingSet operations API call */
-short modifykey_get_context_data (bContext *C, ListBase *dsources, KeyingSet *ks);
-
 /* Operator Define Prototypes ------------------- */
 
 /* Main Keyframe Management operators: 
index d0675dc42ba1f8ddaffb9ac189daf26563172b57..eaebab2efab17a1eb093d921f90170b8532e55d7 100644 (file)
@@ -1073,7 +1073,6 @@ static int modify_key_op_poll(bContext *C)
 
 static int insert_key_exec (bContext *C, wmOperator *op)
 {
-       ListBase dsources = {NULL, NULL};
        Scene *scene= CTX_data_scene(C);
        KeyingSet *ks= NULL;
        int type= RNA_int_get(op->ptr, "type");
@@ -1098,22 +1097,17 @@ static int insert_key_exec (bContext *C, wmOperator *op)
                return OPERATOR_CANCELLED;
        }
        
-       /* get context info for relative Keying Sets */
-       if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
-               /* exit if no suitable data obtained */
-               if (modifykey_get_context_data(C, &dsources, ks) == 0) {
-                       BKE_report(op->reports, RPT_ERROR, "No suitable context info for active Keying Set");
-                       return OPERATOR_CANCELLED;
-               }
-       }
-       
        /* try to insert keyframes for the channels specified by KeyingSet */
-       success= modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+       success= ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
        if (G.f & G_DEBUG)
                BKE_reportf(op->reports, RPT_INFO, "KeyingSet '%s' - Successfully added %d Keyframes \n", ks->name, success);
        
        /* report failure or do updates? */
-       if (success) {
+       if (success == MODIFYKEY_INVALID_CONTEXT) {
+               BKE_report(op->reports, RPT_ERROR, "No suitable context info for active Keying Set");
+               return OPERATOR_CANCELLED;
+       }
+       else if (success) {
                /* if the appropriate properties have been set, make a note that we've inserted something */
                if (RNA_boolean_get(op->ptr, "confirm_success"))
                        BKE_reportf(op->reports, RPT_INFO, "Successfully added %d Keyframes for KeyingSet '%s'", success, ks->name);
@@ -1123,13 +1117,6 @@ static int insert_key_exec (bContext *C, wmOperator *op)
        }
        else
                BKE_report(op->reports, RPT_WARNING, "Keying Set failed to insert any keyframes");
-               
-       
-       /* free temp context-data if available */
-       if (dsources.first) {
-               /* we assume that there is no extra data that needs to be freed from here... */
-               BLI_freelistN(&dsources);
-       }
        
        /* send updates */
        DAG_ids_flush_update(0);
@@ -1191,8 +1178,10 @@ static void insert_key_menu_prompt (bContext *C)
         *      - these are listed in the order in which they were defined for the active scene
         */
        if (scene->keyingsets.first) {
-               for (ks= scene->keyingsets.first; ks; ks= ks->next)
-                       uiItemIntO(layout, ks->name, 0, "ANIM_OT_keyframe_insert_menu", "type", i++);
+               for (ks= scene->keyingsets.first; ks; ks= ks->next) {
+                       if (ANIM_keyingset_context_ok_poll(C, ks))
+                               uiItemIntO(layout, ks->name, 0, "ANIM_OT_keyframe_insert_menu", "type", i++);
+               }
                uiItemS(layout);
        }
        
@@ -1200,9 +1189,8 @@ static void insert_key_menu_prompt (bContext *C)
        i= -1;
        for (ks= builtin_keyingsets.first; ks; ks= ks->next) {
                /* only show KeyingSet if context is suitable */
-               if (keyingset_context_ok_poll(C, ks)) {
+               if (ANIM_keyingset_context_ok_poll(C, ks))
                        uiItemIntO(layout, ks->name, 0, "ANIM_OT_keyframe_insert_menu", "type", i--);
-               }
        }
        
        uiPupMenuEnd(C, pup);
@@ -1261,7 +1249,6 @@ void ANIM_OT_keyframe_insert_menu (wmOperatorType *ot)
 
 static int delete_key_exec (bContext *C, wmOperator *op)
 {
-       ListBase dsources = {NULL, NULL};
        Scene *scene= CTX_data_scene(C);
        KeyingSet *ks= NULL;    
        int type= RNA_int_get(op->ptr, "type");
@@ -1286,22 +1273,17 @@ static int delete_key_exec (bContext *C, wmOperator *op)
                return OPERATOR_CANCELLED;
        }
        
-       /* get context info for relative Keying Sets */
-       if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
-               /* exit if no suitable data obtained */
-               if (modifykey_get_context_data(C, &dsources, ks) == 0) {
-                       BKE_report(op->reports, RPT_ERROR, "No suitable context info for active Keying Set");
-                       return OPERATOR_CANCELLED;
-               }
-       }
-       
        /* try to insert keyframes for the channels specified by KeyingSet */
-       success= modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_DELETE, cfra);
+       success= ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_DELETE, cfra);
        if (G.f & G_DEBUG)
                printf("KeyingSet '%s' - Successfully removed %d Keyframes \n", ks->name, success);
        
        /* report failure or do updates? */
-       if (success) {
+       if (success == MODIFYKEY_INVALID_CONTEXT) {
+               BKE_report(op->reports, RPT_ERROR, "No suitable context info for active Keying Set");
+               return OPERATOR_CANCELLED;
+       }
+       else if (success) {
                /* if the appropriate properties have been set, make a note that we've inserted something */
                if (RNA_boolean_get(op->ptr, "confirm_success"))
                        BKE_reportf(op->reports, RPT_INFO, "Successfully removed %d Keyframes for KeyingSet '%s'", success, ks->name);
@@ -1312,12 +1294,6 @@ static int delete_key_exec (bContext *C, wmOperator *op)
        else
                BKE_report(op->reports, RPT_WARNING, "Keying Set failed to remove any keyframes");
        
-       /* free temp context-data if available */
-       if (dsources.first) {
-               /* we assume that there is no extra data that needs to be freed from here... */
-               BLI_freelistN(&dsources);
-       }
-       
        /* send updates */
        DAG_ids_flush_update(0);
        
index 63323a8519d0e3291ca6e22d9b75c33d83f46514..1e4180a3ae72570a220390c1a98004f1e0232bcc 100644 (file)
@@ -256,14 +256,8 @@ static int remove_active_ks_path_exec (bContext *C, wmOperator *op)
                KS_Path *ksp= BLI_findlink(&ks->paths, ks->active_path-1);
                
                if (ksp) {
-                       /* NOTE: sync this code with BKE_keyingset_free() */
-                       {
-                               /* free RNA-path info */
-                               MEM_freeN(ksp->rna_path);
-                               
-                               /* free path itself */
-                               BLI_freelinkN(&ks->paths, ksp);
-                       }
+                       /* remove the active path from the KeyingSet */
+                       BKE_keyingset_free_path(ks, ksp);
                        
                        /* the active path should now be the previously second-to-last active one */
                        ks->active_path--;
@@ -467,663 +461,136 @@ void ANIM_OT_keyingset_button_remove (wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
-/* ************************************************** */
-/* KEYING SETS - EDITING API  */
-
-/* UI API --------------------------------------------- */
-
-/* Build menu-string of available keying-sets (allocates memory for string)
- * NOTE: mode must not be longer than 64 chars
- */
-char *ANIM_build_keyingsets_menu (ListBase *list, short for_edit)
-{
-       DynStr *pupds= BLI_dynstr_new();
-       KeyingSet *ks;
-       char buf[64];
-       char *str;
-       int i;
-       
-       /* add title first */
-       BLI_dynstr_append(pupds, "Keying Sets%t|");
-       
-       /* add dummy entries for none-active */
-       if (for_edit) { 
-               BLI_dynstr_append(pupds, "Add New%x-1|");
-               BLI_dynstr_append(pupds, " %x0|");
-       }
-       else
-               BLI_dynstr_append(pupds, "No Keying Set%x0|");
-       
-       /* loop through keyingsets, adding them */
-       for (ks=list->first, i=1; ks; ks=ks->next, i++) {
-               if (for_edit == 0)
-                       BLI_dynstr_append(pupds, "KS: ");
-               
-               BLI_dynstr_append(pupds, ks->name);
-               BLI_snprintf( buf, 64, "%%x%d%s", i, ((ks->next)?"|":"") );
-               BLI_dynstr_append(pupds, buf);
-       }
-       
-       /* convert to normal MEM_malloc'd string */
-       str= BLI_dynstr_get_cstring(pupds);
-       BLI_dynstr_free(pupds);
-       
-       return str;
-}
-
-
 /* ******************************************* */
-/* KEYING SETS - BUILTIN */
-
-#if 0 // XXX old keyingsets code based on adrcodes... to be restored in due course
-
-/* ------------- KeyingSet Defines ------------ */
-/* Note: these must all be named with the defks_* prefix, otherwise the template macro will not work! */
-
-/* macro for defining keyingset contexts */
-#define KSC_TEMPLATE(ctx_name) {&defks_##ctx_name[0], NULL, sizeof(defks_##ctx_name)/sizeof(bKeyingSet)}
+/* REGISTERED KEYING SETS */
 
-/* --- */
+/* Keying Set Type Info declarations */
+ListBase keyingset_type_infos = {NULL, NULL};
 
-/* check if option not available for deleting keys */
-static short incl_non_del_keys (bKeyingSet *ks, const char mode[])
-{
-       /* as optimisation, assume that it is sufficient to check only first letter
-        * of mode (int comparison should be faster than string!)
-        */
-       //if (strcmp(mode, "Delete")==0)
-       if (mode && mode[0]=='D')
-               return 0;
-       
-       return 1;
-}
+/* Built-In Keying Sets (referencing type infos)*/
+ListBase builtin_keyingsets = {NULL, NULL};
 
-/* Object KeyingSets  ------ */
+/* --------------- */
 
-/* check if include shapekey entry  */
-static short incl_v3d_ob_shapekey (bKeyingSet *ks, const char mode[])
+/* Find KeyingSet type info given a name */
+KeyingSetInfo *ANIM_keyingset_info_find_named (const char name[])
 {
-       //Object *ob= (G.obedit)? (G.obedit) : (OBACT); // XXX
-       Object *ob= NULL;
-       char *newname= NULL;
-       
-       if(ob==NULL)
-               return 0;
-       
-       /* not available for delete mode */
-       if (strcmp(mode, "Delete")==0)
-               return 0;
+       KeyingSetInfo *ksi;
        
-       /* check if is geom object that can get shapekeys */
-       switch (ob->type) {
-               /* geometry? */
-               case OB_MESH:           newname= "Mesh";                break;
-               case OB_CURVE:          newname= "Curve";               break;
-               case OB_SURF:           newname= "Surface";             break;
-               case OB_LATTICE:        newname= "Lattice";             break;
+       /* sanity checks */
+       if ((name == NULL) || (name[0] == 0))
+               return NULL;
                
-               /* not geometry! */
-               default:
-                       return 0;
+       /* search by comparing names */
+       for (ksi = keyingset_type_infos.first; ksi; ksi = ksi->next) {
+               if (strcmp(ksi->name, name) == 0)
+                       return ksi;
        }
        
-       /* if ks is shapekey entry (this could be callled for separator before too!) */
-       if (ks->flag == -3)
-               BLI_strncpy(ks->name, newname, sizeof(ks->name));
-       
-       /* if it gets here, it's ok */
-       return 1;
+       /* no matches found */
+       return NULL;
 }
 
-/* array for object keyingset defines */
-bKeyingSet defks_v3d_object[] = 
-{
-       /* include_cb, adrcode-getter, name, blocktype, flag, chan_num, adrcodes */
-       {NULL, "Loc", ID_OB, 0, 3, {OB_LOC_X,OB_LOC_Y,OB_LOC_Z}},
-       {NULL, "Rot", ID_OB, 0, 3, {OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
-       {NULL, "Scale", ID_OB, 0, 3, {OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
-       
-       {NULL, "%l", 0, -1, 0, {0}}, // separator
-       
-       {NULL, "LocRot", ID_OB, 0, 6, 
-               {OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
-                OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
-                
-       {NULL, "LocScale", ID_OB, 0, 6, 
-               {OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
-                OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
-                
-       {NULL, "LocRotScale", ID_OB, 0, 9, 
-               {OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
-                OB_ROT_X,OB_ROT_Y,OB_ROT_Z,
-                OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
-                
-       {NULL, "RotScale", ID_OB, 0, 6, 
-               {OB_ROT_X,OB_ROT_Y,OB_ROT_Z,
-                OB_SIZE_X,OB_SIZE_Y,OB_SIZE_Z}},
-       
-       {incl_non_del_keys, "%l", 0, -1, 0, {0}}, // separator
-       
-       {incl_non_del_keys, "VisualLoc", ID_OB, INSERTKEY_MATRIX, 3, {OB_LOC_X,OB_LOC_Y,OB_LOC_Z}},
-       {incl_non_del_keys, "VisualRot", ID_OB, INSERTKEY_MATRIX, 3, {OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
-       
-       {incl_non_del_keys, "VisualLocRot", ID_OB, INSERTKEY_MATRIX, 6, 
-               {OB_LOC_X,OB_LOC_Y,OB_LOC_Z,
-                OB_ROT_X,OB_ROT_Y,OB_ROT_Z}},
-       
-       {NULL, "%l", 0, -1, 0, {0}}, // separator
-       
-       {NULL, "Layer", ID_OB, 0, 1, {OB_LAY}}, // icky option...
-       {NULL, "Available", ID_OB, -2, 0, {0}},
-       
-       {incl_v3d_ob_shapekey, "%l%l", 0, -1, 0, {0}}, // separator (linked to shapekey entry)
-       {incl_v3d_ob_shapekey, "<ShapeKey>", ID_OB, -3, 0, {0}}
-};
-
-/* PoseChannel KeyingSets  ------ */
-
-/* array for posechannel keyingset defines */
-bKeyingSet defks_v3d_pchan[] = 
+/* Find builtin KeyingSet by name */
+KeyingSet *ANIM_builtin_keyingset_get_named (KeyingSet *prevKS, const char name[])
 {
-       /* include_cb, name, blocktype, flag, chan_num, adrcodes */
-       {NULL, "Loc", ID_PO, 0, 3, {AC_LOC_X,AC_LOC_Y,AC_LOC_Z}},
-       {NULL, "Rot", ID_PO, COMMONKEY_PCHANROT, 1, {KAG_CHAN_EXTEND}},
-       {NULL, "Scale", ID_PO, 0, 3, {AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z}},
-       
-       {NULL, "%l", 0, -1, 0, {0}}, // separator
-       
-       {NULL, "LocRot", ID_PO, COMMONKEY_PCHANROT, 4, 
-               {AC_LOC_X,AC_LOC_Y,AC_LOC_Z,
-                KAG_CHAN_EXTEND}},
-                
-       {NULL, "LocScale", ID_PO, 0, 6, 
-               {AC_LOC_X,AC_LOC_Y,AC_LOC_Z,
-                AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z}},
-                
-       {NULL, "LocRotScale", ID_PO, COMMONKEY_PCHANROT, 7, 
-               {AC_LOC_X,AC_LOC_Y,AC_LOC_Z,AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z, 
-                KAG_CHAN_EXTEND}},
-                
-       {NULL, "RotScale", ID_PO, 0, 4, 
-               {AC_SIZE_X,AC_SIZE_Y,AC_SIZE_Z, 
-                KAG_CHAN_EXTEND}},
-       
-       {incl_non_del_keys, "%l", 0, -1, 0, {0}}, // separator
-       
-       {incl_non_del_keys, "VisualLoc", ID_PO, INSERTKEY_MATRIX, 3, {AC_LOC_X,AC_LOC_Y,AC_LOC_Z}},
-       {incl_non_del_keys, "VisualRot", ID_PO, INSERTKEY_MATRIX|COMMONKEY_PCHANROT, 1, {KAG_CHAN_EXTEND}},
-       
-       {incl_non_del_keys, "VisualLocRot", ID_PO, INSERTKEY_MATRIX|COMMONKEY_PCHANROT, 4, 
-               {AC_LOC_X,AC_LOC_Y,AC_LOC_Z, KAG_CHAN_EXTEND}},
-       
-       {NULL, "%l", 0, -1, 0, {0}}, // separator
-       
-       {NULL, "Available", ID_PO, -2, 0, {0}}
-};
-
-/* Material KeyingSets  ------ */
-
-/* array for material keyingset defines */
-bKeyingSet defks_buts_shading_mat[] = 
-{
-       /* include_cb, name, blocktype, flag, chan_num, adrcodes */
-       {NULL, "RGB", ID_MA, 0, 3, {MA_COL_R,MA_COL_G,MA_COL_B}},
-       {NULL, "Alpha", ID_MA, 0, 1, {MA_ALPHA}},
-       {NULL, "Halo Size", ID_MA, 0, 1, {MA_HASIZE}},
-       {NULL, "Mode", ID_MA, 0, 1, {MA_MODE}}, // evil bitflags
-       
-       {NULL, "%l", 0, -1, 0, {0}}, // separator
-       
-       {NULL, "All Color", ID_MA, 0, 18, 
-               {MA_COL_R,MA_COL_G,MA_COL_B,
-                MA_ALPHA,MA_HASIZE, MA_MODE,
-                MA_SPEC_R,MA_SPEC_G,MA_SPEC_B,
-                MA_REF,MA_EMIT,MA_AMB,MA_SPEC,MA_HARD,
-                MA_MODE,MA_TRANSLU,MA_ADD}},
-                
-       {NULL, "All Mirror", ID_MA, 0, 5, 
-               {MA_RAYM,MA_FRESMIR,MA_FRESMIRI,
-                MA_FRESTRA,MA_FRESTRAI}},
-       
-       {NULL, "%l", 0, -1, 0, {0}}, // separator
-       
-       {NULL, "Ofs", ID_MA, COMMONKEY_ADDMAP, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}},
-       {NULL, "Size", ID_MA, COMMONKEY_ADDMAP, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}},
-       
-       {NULL, "All Mapping", ID_MA, COMMONKEY_ADDMAP, 14, 
-               {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z,
-                MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z,
-                MAP_R,MAP_G,MAP_B,MAP_DVAR,
-                MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}},
-       
-       {NULL, "%l", 0, -1, 0, {0}}, // separator
-       
-       {NULL, "Available", ID_MA, -2, 0, {0}}
-};
-
-/* World KeyingSets  ------ */
-
-/* array for world keyingset defines */
-bKeyingSet defks_buts_shading_wo[] = 
-{
-       /* include_cb, name, blocktype, flag, chan_num, adrcodes */
-       {NULL, "Zenith RGB", ID_WO, 0, 3, {WO_ZEN_R,WO_ZEN_G,WO_ZEN_B}},
-       {NULL, "Horizon RGB", ID_WO, 0, 3, {WO_HOR_R,WO_HOR_G,WO_HOR_B}},
-       
-       {NULL, "%l", 0, -1, 0, {0}}, // separator
-       
-       {NULL, "Mist", ID_WO, 0, 4, {WO_MISI,WO_MISTDI,WO_MISTSTA,WO_MISTHI}},
-       {NULL, "Stars", ID_WO, 0, 5, {WO_STAR_R,WO_STAR_G,WO_STAR_B,WO_STARDIST,WO_STARSIZE}},
-       
-       
-       {NULL, "%l", 0, -1, 0, {0}}, // separator
-       
-       {NULL, "Ofs", ID_WO, COMMONKEY_ADDMAP, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}},
-       {NULL, "Size", ID_WO, COMMONKEY_ADDMAP, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}},
-       
-       {NULL, "All Mapping", ID_WO, COMMONKEY_ADDMAP, 14, 
-               {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z,
-                MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z,
-                MAP_R,MAP_G,MAP_B,MAP_DVAR,
-                MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}},
-       
-       {NULL, "%l", 0, -1, 0, {0}}, // separator
-       
-       {NULL, "Available", ID_WO, -2, 0, {0}}
-};
-
-/* Lamp KeyingSets  ------ */
-
-/* array for lamp keyingset defines */
-bKeyingSet defks_buts_shading_la[] = 
-{
-       /* include_cb, name, blocktype, flag, chan_num, adrcodes */
-       {NULL, "RGB", ID_LA, 0, 3, {LA_COL_R,LA_COL_G,LA_COL_B}},
-       {NULL, "Energy", ID_LA, 0, 1, {LA_ENERGY}},
-       {NULL, "Spot Size", ID_LA, 0, 1, {LA_SPOTSI}},
-       
-       {NULL, "%l", 0, -1, 0, {0}}, // separator
-       
-       {NULL, "Ofs", ID_LA, COMMONKEY_ADDMAP, 3, {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z}},
-       {NULL, "Size", ID_LA, COMMONKEY_ADDMAP, 3, {MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z}},
-       
-       {NULL, "All Mapping", ID_LA, COMMONKEY_ADDMAP, 14, 
-               {MAP_OFS_X,MAP_OFS_Y,MAP_OFS_Z,
-                MAP_SIZE_X,MAP_SIZE_Y,MAP_SIZE_Z,
-                MAP_R,MAP_G,MAP_B,MAP_DVAR,
-                MAP_COLF,MAP_NORF,MAP_VARF,MAP_DISP}},
+       KeyingSet *ks, *first=NULL;
        
-       {NULL, "%l", 0, -1, 0, {0}}, // separator
+       /* sanity checks  any name to check? */
+       if (name[0] == 0)
+               return NULL;
        
-       {NULL, "Available", ID_LA, -2, 0, {0}}
-};
-
-/* Texture KeyingSets  ------ */
-
-/* array for texture keyingset defines */
-bKeyingSet defks_buts_shading_tex[] = 
-{
-       /* include_cb, name, blocktype, flag, chan_num, adrcodes */
-       {NULL, "Clouds", ID_TE, 0, 5, 
-               {TE_NSIZE,TE_NDEPTH,TE_NTYPE,
-                TE_MG_TYP,TE_N_BAS1}},
-       
-       {NULL, "Marble", ID_TE, 0, 7, 
-               {TE_NSIZE,TE_NDEPTH,TE_NTYPE,
-                TE_TURB,TE_MG_TYP,TE_N_BAS1,TE_N_BAS2}},
-                
-       {NULL, "Stucci", ID_TE, 0, 5, 
-               {TE_NSIZE,TE_NTYPE,TE_TURB,
-                TE_MG_TYP,TE_N_BAS1}},
-                
-       {NULL, "Wood", ID_TE, 0, 6, 
-               {TE_NSIZE,TE_NTYPE,TE_TURB,
-                TE_MG_TYP,TE_N_BAS1,TE_N_BAS2}},
-                
-       {NULL, "Magic", ID_TE, 0, 2, {TE_NDEPTH,TE_TURB}},
-       
-       {NULL, "Blend", ID_TE, 0, 1, {TE_MG_TYP}},      
-               
-       {NULL, "Musgrave", ID_TE, 0, 6, 
-               {TE_MG_TYP,TE_MGH,TE_MG_LAC,
-                TE_MG_OCT,TE_MG_OFF,TE_MG_GAIN}},
-                
-       {NULL, "Voronoi", ID_TE, 0, 9, 
-               {TE_VNW1,TE_VNW2,TE_VNW3,TE_VNW4,
-               TE_VNMEXP,TE_VN_DISTM,TE_VN_COLT,
-               TE_ISCA,TE_NSIZE}},
+       /* get first KeyingSet to use */
+       if (prevKS && prevKS->next)
+               first= prevKS->next;
+       else
+               first= builtin_keyingsets.first;
                
-       {NULL, "Distorted Noise", ID_TE, 0, 4, 
-               {TE_MG_OCT,TE_MG_OFF,TE_MG_GAIN,TE_DISTA}},
-       
-       {NULL, "Color Filter", ID_TE, 0, 5, 
-               {TE_COL_R,TE_COL_G,TE_COL_B,TE_BRIGHT,TE_CONTRA}},
-       
-       {NULL, "%l", 0, -1, 0, {0}}, // separator
-       
-       {NULL, "Available", ID_TE, -2, 0, {0}}
-};
-
-/* Object Buttons KeyingSets  ------ */
-
-/* check if include particles entry  */
-static short incl_buts_ob (bKeyingSet *ks, const char mode[])
-{
-       //Object *ob= OBACT; // xxx
-       Object *ob= NULL;
-       /* only if object is mesh type */
-       
-       if(ob==NULL) return 0;
-       return (ob->type == OB_MESH);
-}
-
-/* array for texture keyingset defines */
-bKeyingSet defks_buts_object[] = 
-{
-       /* include_cb, name, blocktype, flag, chan_num, adrcodes */
-       {incl_buts_ob, "Surface Damping", ID_OB, 0, 1, {OB_PD_SDAMP}},
-       {incl_buts_ob, "Random Damping", ID_OB, 0, 1, {OB_PD_RDAMP}},
-       {incl_buts_ob, "Permeability", ID_OB, 0, 1, {OB_PD_PERM}},
-       
-       {NULL, "%l", 0, -1, 0, {0}}, // separator
-       
-       {NULL, "Force Strength", ID_OB, 0, 1, {OB_PD_FSTR}},
-       {NULL, "Force Falloff", ID_OB, 0, 1, {OB_PD_FFALL}},
-       
-       {NULL, "%l", 0, -1, 0, {0}}, // separator
+       /* loop over KeyingSets checking names */
+       for (ks= first; ks; ks= ks->next) {
+               if (strcmp(name, ks->name) == 0)
+                       return ks;
+       }
        
-       {NULL, "Available", ID_OB, -2, 0, {0}}  // this will include ob-transforms too!
-};
-
-/* Camera Buttons KeyingSets  ------ */
-
-/* check if include internal-renderer entry  */
-static short incl_buts_cam1 (bKeyingSet *ks, const char mode[])
-{
-       Scene *scene= NULL; // FIXME this will cause a crash, but we need an extra arg first!
-       /* only if renderer is internal renderer */
-       return (scene->r.renderer==R_INTERN);
+       /* no matches found */
+       return NULL;
 }
 
-/* check if include external-renderer entry  */
-static short incl_buts_cam2 (bKeyingSet *ks, const char mode[])
-{
-       Scene *scene= NULL; // FIXME this will cause a crash, but we need an extra arg first!
-       /* only if renderer is internal renderer */
-       return (scene->r.renderer!=R_INTERN);
-}
+/* --------------- */
 
-/* array for camera keyingset defines */
-bKeyingSet defks_buts_cam[] = 
+/* Add the given KeyingSetInfo to the list of type infos, and create an appropriate builtin set too */
+void ANIM_keyingset_info_register (const bContext *C, KeyingSetInfo *ksi)
 {
-       /* include_cb, name, blocktype, flag, chan_num, adrcodes */
-       {NULL, "Lens", ID_CA, 0, 1, {CAM_LENS}},
-       {NULL, "Clipping", ID_CA, 0, 2, {CAM_STA,CAM_END}},
-       {NULL, "Focal Distance", ID_CA, 0, 1, {CAM_YF_FDIST}},
-       
-       {NULL, "%l", 0, -1, 0, {0}}, // separator
+       Scene *scene = CTX_data_scene(C);
+       ListBase *list = NULL;
+       KeyingSet *ks;
        
+       /* determine the KeyingSet list to include the new KeyingSet in */
+       if (ksi->builtin)
+               list = &builtin_keyingsets;
+       else
+               list = &scene->keyingsets;
        
-       {incl_buts_cam2, "Aperture", ID_CA, 0, 1, {CAM_YF_APERT}},
-       {incl_buts_cam1, "Viewplane Shift", ID_CA, 0, 2, {CAM_SHIFT_X,CAM_SHIFT_Y}},
+       /* create a new KeyingSet 
+        *      - inherit name and keyframing settings from the typeinfo
+        */
+       ks = BKE_keyingset_add(list, ksi->name, ksi->builtin, ksi->keyingflag);
        
-       {NULL, "%l", 0, -1, 0, {0}}, // separator
+       /* link this KeyingSet with its typeinfo */
+       memcpy(&ks->typeinfo, ksi->name, sizeof(ks->typeinfo));
        
-       {NULL, "Available", ID_CA, -2, 0, {0}}
-};
-
-/* --- */
+       /* add type-info to the list */
+       BLI_addtail(&keyingset_type_infos, ksi);
+}
 
-/* Keying Context Defines - Must keep in sync with enumeration (eKS_Contexts) */
-bKeyingContext ks_contexts[] = 
+/* Remove the given KeyingSetInfo from the list of type infos, and also remove the builtin set if appropriate */
+void ANIM_keyingset_info_unregister (const bContext *C, KeyingSetInfo *ksi)
 {
-       KSC_TEMPLATE(v3d_object),
-       KSC_TEMPLATE(v3d_pchan),
+       Scene *scene = CTX_data_scene(C);
+       KeyingSet *ks, *ksn;
        
-       KSC_TEMPLATE(buts_shading_mat),
-       KSC_TEMPLATE(buts_shading_wo),
-       KSC_TEMPLATE(buts_shading_la),
-       KSC_TEMPLATE(buts_shading_tex),
-
-       KSC_TEMPLATE(buts_object),
-       KSC_TEMPLATE(buts_cam)
-};
-
-/* Keying Context Enumeration - Must keep in sync with definitions*/
-typedef enum eKS_Contexts {
-       KSC_V3D_OBJECT = 0,
-       KSC_V3D_PCHAN,
-       
-       KSC_BUTS_MAT,
-       KSC_BUTS_WO,
-       KSC_BUTS_LA,
-       KSC_BUTS_TEX,
-       
-       KSC_BUTS_OB,
-       KSC_BUTS_CAM,
-       
-               /* make sure this last one remains untouched! */
-       KSC_TOT_TYPES
-} eKS_Contexts;
-
-
-#endif // XXX old keyingsets code based on adrcodes... to be restored in due course
-
-/* Macros for Declaring KeyingSets ------------------- */
-
-/* A note about this system for declaring built-in Keying Sets:
- *     One may ask, "What is the purpose of all of these macros and static arrays?" and 
- *     "Why not call the KeyingSets API defined in BKE_animsys.h?". The answer is two-fold.
- *     
- *     1) Firstly, we use static arrays of struct definitions instead of function calls, as
- *        it reduces the start-up overhead and allocated-memory footprint of Blender. If we called
- *        the KeyingSets API to build these sets, the overhead of checking for unique names, allocating
- *        memory for each and every path and KeyingSet, scattered around in RAM, all of which would increase
- *        the startup time (which is totally unacceptable) and could lead to fragmentation+slower access times.
- *     2) Since we aren't using function calls, we need a nice way of defining these KeyingSets in a way which
- *        is easily readable and less prone to breakage from changes to the underlying struct definitions. Further,
- *        adding additional entries SHOULD NOT require custom code to be written to access these new entries/sets. 
- *        Therefore, here we have a system with nice, human-readable statements via macros, and static arrays which
- *        are linked together using more special macros + struct definitions, allowing for such a generic + simple
- *        initialisation function (init_builtin_keyingsets()) compared with that of something like the Nodes system.
- *
- * -- Joshua Leung, April 2009
- */
-
-/* Struct type for declaring builtin KeyingSets in as entries in static arrays*/
-typedef struct bBuiltinKeyingSet {
-       KeyingSet ks;                   /* the KeyingSet to build */
-       int tot;                                /* the total number of paths defined */
-       KS_Path paths[64];              /* the paths for the KeyingSet to use */
-} bBuiltinKeyingSet;
-
-       /* WARNING: the following macros must be kept in sync with the 
-        * struct definitions in DNA_anim_types.h! 
-        */
-
-/* macro for defining a builtin KeyingSet */
-#define BI_KS_DEFINE_BEGIN(name, keyingflag) \
-       {{NULL, NULL, {NULL, NULL}, name, KEYINGSET_BUILTIN, keyingflag},
-       
-/* macro to finish defining a builtin KeyingSet */
-#define BI_KS_DEFINE_END \
-       }
-       
-/* macro to start defining paths for a builtin KeyingSet */
-#define BI_KS_PATHS_BEGIN(tot) \
-       tot, {
-       
-/* macro to finish defining paths for a builtin KeyingSet */
-#define BI_KS_PATHS_END \
+       /* find relevant scene KeyingSets which use this, and remove them */
+       for (ks= scene->keyingsets.first; ks; ks= ksn) {
+               ksn = ks->next;
+               
+               /* remove if matching typeinfo name */
+               if (strcmp(ks->typeinfo, ksi->name) == 0) {
+                       BKE_keyingset_free(ks);
+                       BLI_freelinkN(&scene->keyingsets, ks);
+               }
        }
        
-/* macro for defining a builtin KeyingSet's path */
-#define BI_KSP_DEFINE(id_type, templates, prop_path, array_index, flag, groupflag) \
-       {NULL, NULL, NULL, "", id_type, templates, prop_path, array_index, flag, groupflag}
+       /* do the same with builtin sets? */
+       // TODO: this isn't done now, since unregister is really only used atm when we
+       // reload the scripts, which kindof defeats the purpose of "builtin"?
        
-/* macro for defining a builtin KeyingSet with no paths (use in place of BI_KS_PAHTS_BEGIN/END block) */
-#define BI_KS_PATHS_NONE \
-       0, {0}
        
-/* ---- */
-
-/* Struct type for finding all the arrays of builtin KeyingSets */
-typedef struct bBuiltinKSContext {
-       bBuiltinKeyingSet *bks;         /* array of KeyingSet definitions */
-       int tot;                                        /* number of KeyingSets in this array */
-} bBuiltinKSContext;
-
-/* macro for defining builtin KeyingSet sets 
- * NOTE: all the arrays of sets must follow this naming convention!
- */
-#define BKSC_TEMPLATE(ctx_name) {&def_builtin_keyingsets_##ctx_name[0], sizeof(def_builtin_keyingsets_##ctx_name)/sizeof(bBuiltinKeyingSet)}
-
-
-/* 3D-View Builtin KeyingSets ------------------------ */
-
-static bBuiltinKeyingSet def_builtin_keyingsets_v3d[] =
-{
-       /* Simple Keying Sets ************************************* */
-       /* Keying Set - "Location" ---------- */
-       BI_KS_DEFINE_BEGIN("Location", 0)
-               BI_KS_PATHS_BEGIN(1)
-                       BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "location", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) 
-               BI_KS_PATHS_END
-       BI_KS_DEFINE_END,
-
-       /* Keying Set - "Rotation" ---------- */
-       BI_KS_DEFINE_BEGIN("Rotation", 0)
-               BI_KS_PATHS_BEGIN(1)
-                       BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN|KSP_TEMPLATE_ROT, "rotation", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) 
-               BI_KS_PATHS_END
-       BI_KS_DEFINE_END,
-       
-       /* Keying Set - "Scaling" ---------- */
-       BI_KS_DEFINE_BEGIN("Scaling", 0)
-               BI_KS_PATHS_BEGIN(1)
-                       BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "scale", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) 
-               BI_KS_PATHS_END
-       BI_KS_DEFINE_END,
-       
-       /* Compound Keying Sets *********************************** */
-       /* Keying Set - "LocRot" ---------- */
-       BI_KS_DEFINE_BEGIN("LocRot", 0)
-               BI_KS_PATHS_BEGIN(2)
-                       BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "location", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM), 
-                       BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN|KSP_TEMPLATE_ROT, "rotation", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) 
-               BI_KS_PATHS_END
-       BI_KS_DEFINE_END,
-       
-       /* Keying Set - "LocRotScale" ---------- */
-       BI_KS_DEFINE_BEGIN("LocRotScale", 0)
-               BI_KS_PATHS_BEGIN(3)
-                       BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "location", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM), 
-                       BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN|KSP_TEMPLATE_ROT, "rotation", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM), 
-                       BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "scale", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) 
-               BI_KS_PATHS_END
-       BI_KS_DEFINE_END,
-       
-       /* Keying Sets with Keying Flags ************************* */
-       /* Keying Set - "VisualLoc" ---------- */
-       BI_KS_DEFINE_BEGIN("VisualLoc", INSERTKEY_MATRIX)
-               BI_KS_PATHS_BEGIN(1)
-                       BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "location", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) 
-               BI_KS_PATHS_END
-       BI_KS_DEFINE_END,
-
-       /* Keying Set - "Rotation" ---------- */
-       BI_KS_DEFINE_BEGIN("VisualRot", INSERTKEY_MATRIX)
-               BI_KS_PATHS_BEGIN(1)
-                       BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN|KSP_TEMPLATE_ROT, "rotation", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) 
-               BI_KS_PATHS_END
-       BI_KS_DEFINE_END,
-       
-       /* Keying Set - "VisualLocRot" ---------- */
-       BI_KS_DEFINE_BEGIN("VisualLocRot", INSERTKEY_MATRIX)
-               BI_KS_PATHS_BEGIN(2)
-                       BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN, "location", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM), 
-                       BI_KSP_DEFINE(ID_OB, KSP_TEMPLATE_OBJECT|KSP_TEMPLATE_PCHAN|KSP_TEMPLATE_ROT, "rotation", 0, KSP_FLAG_WHOLE_ARRAY, KSP_GROUP_TEMPLATE_ITEM) 
-               BI_KS_PATHS_END
-       BI_KS_DEFINE_END
-};
-
-/* All Builtin KeyingSets ------------------------ */
-
-/* total number of builtin KeyingSet contexts */
-#define MAX_BKSC_TYPES         1
-
-/* array containing all the available builtin KeyingSets definition sets 
- *     - size of this is MAX_BKSC_TYPES+1 so that we don't smash the stack
- */
-static bBuiltinKSContext def_builtin_keyingsets[MAX_BKSC_TYPES+1] =
-{
-       BKSC_TEMPLATE(v3d)
-       /* add more contexts above this line... */
-};
-
-
-/* ListBase of these KeyingSets chained up ready for usage 
- * NOTE: this is exported to keyframing.c for use...
- */
-ListBase builtin_keyingsets = {NULL, NULL};
-
-/* Utility API ------------------------ */
-
-/* Link up all of the builtin Keying Sets when starting up Blender
- * This is called from WM_init() in wm_init_exit.c
- */
-void init_builtin_keyingsets (void)
-{
-       bBuiltinKSContext *bksc;
-       bBuiltinKeyingSet *bks;
-       int bksc_i, bks_i;
-       
-       /* loop over all the sets of KeyingSets, setting them up, and chaining them to the builtins list */
-       for (bksc_i= 0, bksc= &def_builtin_keyingsets[0]; bksc_i < MAX_BKSC_TYPES; bksc_i++, bksc++)
-       {
-               /* for each set definitions for a builtin KeyingSet, chain the paths to that KeyingSet and add */
-               for (bks_i= 0, bks= bksc->bks; bks_i < bksc->tot; bks_i++, bks++)
-               {
-                       KeyingSet *ks= &bks->ks;
-                       KS_Path *ksp;
-                       int pIndex;
-                       
-                       /* loop over paths, linking them to the KeyingSet and each other */
-                       for (pIndex= 0, ksp= &bks->paths[0]; pIndex < bks->tot; pIndex++, ksp++)
-                               BLI_addtail(&ks->paths, ksp);
-                               
-                       /* add KeyingSet to builtin sets list */
-                       BLI_addtail(&builtin_keyingsets, ks);
-               }
-       }
+       /* free the type info */
+       BLI_freelinkN(&keyingset_type_infos, ksi);
 }
 
+/* --------------- */
 
-/* Get the first builtin KeyingSet with the given name, which occurs after the given one (or start of list if none given) */
-KeyingSet *ANIM_builtin_keyingset_get_named (KeyingSet *prevKS, char name[])
+void ANIM_keyingset_infos_exit ()
 {
-       KeyingSet *ks, *first=NULL;
-       
-       /* sanity checks - any name to check? */
-       if (name[0] == 0)
-               return NULL;
+       KeyingSetInfo *ksi, *next;
        
-       /* get first KeyingSet to use */
-       if (prevKS && prevKS->next)
-               first= prevKS->next;
-       else
-               first= builtin_keyingsets.first;
+       /* free type infos */
+       for (ksi=keyingset_type_infos.first; ksi; ksi=next) {
+               next= ksi->next;
                
-       /* loop over KeyingSets checking names */
-       for (ks= first; ks; ks= ks->next) {
-               if (strcmp(name, ks->name) == 0)
-                       return ks;
+               /* free extra RNA data, and remove from list */
+               if (ksi->ext.free)
+                       ksi->ext.free(ksi->ext.data);
+               BLI_freelinkN(&keyingset_type_infos, ksi);
        }
        
-       /* no matches found */
-       return NULL;
+       /* free builtin sets */
+       BKE_keyingsets_free(&builtin_keyingsets);
 }
 
+/* ******************************************* */
+/* KEYING SETS API (for UI) */
 
 /* Get the active Keying Set for the Scene provided */
 KeyingSet *ANIM_scene_get_active_keyingset (Scene *scene)
@@ -1142,127 +609,74 @@ KeyingSet *ANIM_scene_get_active_keyingset (Scene *scene)
                return NULL; 
 }
 
-/* ******************************************* */
-/* KEYFRAME MODIFICATION */
-
-/* KeyingSet Menu Helpers ------------ */
-
-/* Extract the maximum set of requirements from the KeyingSet */
-static int keyingset_relative_get_templates (KeyingSet *ks)
+/* Check if KeyingSet can be used in the current context */
+short ANIM_keyingset_context_ok_poll (bContext *C, KeyingSet *ks)
 {
-       KS_Path *ksp;
-       int templates= 0;
-       
-       /* loop over the paths (could be slow to do for a number of KeyingSets)? */
-       for (ksp= ks->paths.first; ksp; ksp= ksp->next) {
-               /* add the destination's templates to the set of templates required for the set */
-               templates |= ksp->templates;
+       if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
+               KeyingSetInfo *ksi = ANIM_keyingset_info_find_named(ks->typeinfo);
+               
+               /* get the associated 'type info' for this KeyingSet */
+               if (ksi == NULL)
+                       return 0;
+               // TODO: check for missing callbacks!
+               
+               /* check if it can be used in the current context */
+               return (ksi->poll(ksi, C));
        }
        
-       return templates;
-}
-
-/* Check if context data is suitable for the given Keying Set */
-short keyingset_context_ok_poll (bContext *C, KeyingSet *ks)
-{
-       // TODO:
-       //      For 'relative' keyingsets (i.e. py-keyingsets), add a call here
-       //      which basically gets a listing of all the paths to be used for this
-       //      set.
-       
-       
        return 1;
 }
 
-/* KeyingSet Context Operations ------------ */
+/* ******************************************* */
+/* KEYFRAME MODIFICATION */
+
+/* Special 'Overrides' Iterator for Relative KeyingSets ------ */
+
+/* 'Data Sources' for relative Keying Set 'overrides' 
+ *     - this is basically a wrapper for PointerRNA's in a linked list
+ *     - do not allow this to be accessed from outside for now
+ */
+typedef struct tRKS_DSource {
+       struct tRKS_DSource *next, *prev;
+       PointerRNA ptr;         /* the whole point of this exercise! */
+} tRKS_DSource;
+
 
-/* Get list of data-sources from context (in 3D-View) for inserting keyframes using the given relative Keying Set */
-static short modifykey_get_context_v3d_data (bContext *C, ListBase *dsources, KeyingSet *ks)
+/* Iterator used for overriding the behaviour of iterators defined for 
+ * relative Keying Sets, with the main usage of this being operators 
+ * requiring Auto Keyframing. Internal Use Only!
+ */
+static void RKS_ITER_overrides_list (KeyingSetInfo *ksi, bContext *C, KeyingSet *ks, ListBase *dsources)
 {
-       bCommonKeySrc *cks;
-       Object *obact= CTX_data_active_object(C);
-       int templates; 
-       short ok= 0;
-       
-       /* get the templates in use in this KeyingSet which we should supply data for */
-       templates = keyingset_relative_get_templates(ks);
-       
-       /* check if the active object is in PoseMode (i.e. only deal with bones) */
-       // TODO: check with the templates to see what we really need to store 
-       if ((obact && obact->pose) && (obact->mode & OB_MODE_POSE)) {
-               /* Pose Mode: Selected bones */
-#if 0
-               //set_pose_keys(ob);  /* sets pchan->flag to POSE_KEY if bone selected, and clears if not */
-               
-               /* loop through posechannels */
-               //for (pchan=ob->pose->chanbase.first; pchan; pchan=pchan->next) {
-               //      if (pchan->flag & POSE_KEY) {
-               //      }
-               //}
-#endif
-               
-               CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones)
-               {
-                       /* add a new keying-source */
-                       cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
-                       BLI_addtail(dsources, cks);
-                       
-                       /* set necessary info */
-                       cks->id= &obact->id;
-                       cks->pchan= pchan;
-                       
-                       if (templates & KSP_TEMPLATE_CONSTRAINT)
-                               cks->con= constraints_get_active(&pchan->constraints);
-                       
-                       ok= 1;
-               }
-               CTX_DATA_END;
-       }
-       else {
-               /* Object Mode: Selected objects */
-               CTX_DATA_BEGIN(C, Object*, ob, selected_objects) 
-               {                       
-                       /* add a new keying-source */
-                       cks= MEM_callocN(sizeof(bCommonKeySrc), "bCommonKeySrc");
-                       BLI_addtail(dsources, cks);
-                       
-                       /* set necessary info */
-                       cks->id= &ob->id;
-                       
-                       if (templates & KSP_TEMPLATE_CONSTRAINT)
-                               cks->con= constraints_get_active(&ob->constraints);
-                       
-                       ok= 1;
-               }
-               CTX_DATA_END;
-       }
+       tRKS_DSource *ds;
        
-       /* return whether any data was extracted */
-       return ok;
+       for (ds = dsources->first; ds; ds = ds->next) {
+               /* run generate callback on this data */
+               ksi->generate(ksi, C, ks, &ds->ptr);
+       }
 }
 
-/* Get list of data-sources from context for inserting keyframes using the given relative Keying Set */
-short modifykey_get_context_data (bContext *C, ListBase *dsources, KeyingSet *ks)
+/* Add new data source for relative Keying Sets */
+void ANIM_relative_keyingset_add_source (ListBase *dsources, ID *id, StructRNA *srna, void *data)
 {
-       ScrArea *sa= CTX_wm_area(C);
+       tRKS_DSource *ds;
        
-       /* for now, the active area is used to determine what set of contexts apply */
-       if (sa == NULL)
-               return 0;
+       /* sanity checks 
+        *      we must have at least one valid data pointer to use 
+        */
+       if (ELEM(NULL, dsources, srna) || ((id == data) && (id == NULL)))
+               return;
 
-#if 0
-       switch (sa->spacetype) {
-               case SPACE_VIEW3D:      /* 3D-View: Selected Objects or Bones */
-                       return modifykey_get_context_v3d_data(C, dsources, ks);
-       }
+       /* allocate new elem, and add to the list */
+       ds = MEM_callocN(sizeof(tRKS_DSource), "tRKS_DSource");
+       BLI_addtail(dsources, ds);
        
-       /* nothing happened */
-       return 0;
-#endif
-
-       /* looking into this code, it doesnt use the 3D view - Campbell */
-       return modifykey_get_context_v3d_data(C, dsources, ks);
-} 
+       /* depending on what data we have, create using ID or full pointer call */
+       if (srna && data)
+               RNA_pointer_create(id, srna, data, &ds->ptr);
+       else
+               RNA_id_pointer_create(id, &ds->ptr);
+}
 
 /* KeyingSet Operations (Insert/Delete Keyframes) ------------ */
 
@@ -1270,8 +684,9 @@ short modifykey_get_context_data (bContext *C, ListBase *dsources, KeyingSet *ks
  * by the KeyingSet. This takes into account many of the different combinations of using KeyingSets.
  * Returns the number of channels that keyframes were added to
  */
-int modify_keyframes (Scene *scene, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra)
+int ANIM_apply_keyingset (bContext *C, ListBase *dsources, bAction *act, KeyingSet *ks, short mode, float cfra)
 {
+       Scene *scene= CTX_data_scene(C);
        KS_Path *ksp;
        int kflag=0, success= 0;
        char *groupname= NULL;
@@ -1291,201 +706,101 @@ int modify_keyframes (Scene *scene, ListBase *dsources, bAction *act, KeyingSet
        else if (mode == MODIFYKEY_MODE_DELETE)
                kflag= 0;
        
-       /* check if the KeyingSet is absolute or not (i.e. does it requires sources info) */
-       if (ks->flag & KEYINGSET_ABSOLUTE) {
-               /* Absolute KeyingSets are simpler to use, as all the destination info has already been
-                * provided by the user, and is stored, ready to use, in the KeyingSet paths.
+       /* if relative Keying Sets, poll and build up the paths */
+       if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
+               KeyingSetInfo *ksi = ANIM_keyingset_info_find_named(ks->typeinfo);
+               
+               /* clear all existing paths 
+                * NOTE: BKE_keyingset_free() frees all of the paths for the KeyingSet, but not the set itself
                 */
-               for (ksp= ks->paths.first; ksp; ksp= ksp->next) {
-                       int arraylen, i;
-                       
-                       /* get pointer to name of group to add channels to */
-                       if (ksp->groupmode == KSP_GROUP_NONE)
-                               groupname= NULL;
-                       else if (ksp->groupmode == KSP_GROUP_KSNAME)
-                               groupname= ks->name;
-                       else
-                               groupname= ksp->group;
-                       
-                       /* init arraylen and i - arraylen should be greater than i so that
-                        * normal non-array entries get keyframed correctly
-                        */
-                       i= ksp->array_index;
-                       arraylen= i;
-                       
-                       /* get length of array if whole array option is enabled */
-                       if (ksp->flag & KSP_FLAG_WHOLE_ARRAY) {
-                               PointerRNA id_ptr, ptr;
-                               PropertyRNA *prop;
-                               
-                               RNA_id_pointer_create(ksp->id, &id_ptr);
-                               if (RNA_path_resolve(&id_ptr, ksp->rna_path, &ptr, &prop) && prop)
-                                       arraylen= RNA_property_array_length(&ptr, prop);
-                       }
-                       
-                       /* we should do at least one step */
-                       if (arraylen == i)
-                               arraylen++;
-                       
-                       /* for each possible index, perform operation 
-                        *      - assume that arraylen is greater than index
+               BKE_keyingset_free(ks);
+               
+               /* get the associated 'type info' for this KeyingSet */
+               if (ksi == NULL)
+                       return MODIFYKEY_MISSING_TYPEINFO;
+               // TODO: check for missing callbacks!
+               
+               /* check if it can be used in the current context */
+               if (ksi->poll(ksi, C)) {
+                       /* if a list of data sources are provided, run a special iterator over them,
+                        * otherwise, just continue per normal
                         */
-                       for (; i < arraylen; i++) {
-                               /* action to take depends on mode */
-                               if (mode == MODIFYKEY_MODE_INSERT)
-                                       success += insert_keyframe(ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag);
-                               else if (mode == MODIFYKEY_MODE_DELETE)
-                                       success += delete_keyframe(ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag);
-                       }
-                       
-                       /* set recalc-flags */
-                       if (ksp->id) {
-                               switch (GS(ksp->id->name)) {
-                                       case ID_OB: /* Object (or Object-Related) Keyframes */
-                                       {
-                                               Object *ob= (Object *)ksp->id;
-                                               
-                                               ob->recalc |= OB_RECALC;
-                                       }
-                                               break;
-                               }
+                       if (dsources) 
+                               RKS_ITER_overrides_list(ksi, C, ks, dsources);
+                       else
+                               ksi->iter(ksi, C, ks);
                                
-                               /* send notifiers for updates (this doesn't require context to work!) */
-                               WM_main_add_notifier(NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
-                       }
+                       /* if we don't have any paths now, then this still qualifies as invalid context */
+                       if (ks->paths.first == NULL)
+                               return MODIFYKEY_INVALID_CONTEXT;
+               }
+               else {
+                       /* poll callback tells us that KeyingSet is useless in current context */
+                       return MODIFYKEY_INVALID_CONTEXT;
                }
        }
-       else if (dsources && dsources->first) {
-               /* for each one of the 'sources', resolve the template markers and expand arrays, then insert keyframes */
-               bCommonKeySrc *cks;
+       
+       /* apply the paths as specified in the KeyingSet now */
+       for (ksp= ks->paths.first; ksp; ksp= ksp->next) { 
+               int arraylen, i;
+               short kflag2;
                
-               /* for each 'source' for keyframe data, resolve each of the paths from the KeyingSet */
-               for (cks= dsources->first; cks; cks= cks->next) {
-                       /* for each path in KeyingSet, construct a path using the templates */
-                       for (ksp= ks->paths.first; ksp; ksp= ksp->next) {
-                               DynStr *pathds= BLI_dynstr_new();
-                               char *path = NULL;
-                               int arraylen, i;
-                               
-                               /* set initial group name */
-                               if (cks->id == NULL) {
-                                       printf("ERROR: Skipping 'Common-Key' Source. No valid ID present.\n");
-                                       continue;
-                               }
-                               else
-                                       groupname= cks->id->name+2;
-                               
-                               /* construct the path */
-                               // FIXME: this currently only works with a few hardcoded cases
-                               if ((ksp->templates & KSP_TEMPLATE_PCHAN) && (cks->pchan)) {
-                                       /* add basic pose-channel path access */
-                                       BLI_dynstr_append(pathds, "pose.bones[\"");
-                                       BLI_dynstr_append(pathds, cks->pchan->name);
-                                       BLI_dynstr_append(pathds, "\"]");
-                                       
-                                       /* override default group name */
-                                       groupname= cks->pchan->name;
-                               }
-                               if ((ksp->templates & KSP_TEMPLATE_CONSTRAINT) && (cks->con)) {
-                                       /* add basic constraint path access */
-                                       BLI_dynstr_append(pathds, "constraints[\"");
-                                       BLI_dynstr_append(pathds, cks->con->name);
-                                       BLI_dynstr_append(pathds, "\"]");
-                                       
-                                       /* override default group name */
-                                       groupname= cks->con->name;
-                               }
+               /* since keying settings can be defined on the paths too, extend the path before using it */
+               kflag2 = (kflag | ksp->keyingflag);
+               
+               /* get pointer to name of group to add channels to */
+               if (ksp->groupmode == KSP_GROUP_NONE)
+                       groupname= NULL;
+               else if (ksp->groupmode == KSP_GROUP_KSNAME)
+                       groupname= ks->name;
+               else
+                       groupname= ksp->group;
+               
+               /* init arraylen and i - arraylen should be greater than i so that
+                * normal non-array entries get keyframed correctly
+                */
+               i= ksp->array_index;
+               arraylen= i;
+               
+               /* get length of array if whole array option is enabled */
+               if (ksp->flag & KSP_FLAG_WHOLE_ARRAY) {
+                       PointerRNA id_ptr, ptr;
+                       PropertyRNA *prop;
+                       
+                       RNA_id_pointer_create(ksp->id, &id_ptr);
+                       if (RNA_path_resolve(&id_ptr, ksp->rna_path, &ptr, &prop) && prop)
+                               arraylen= RNA_property_array_length(&ptr, prop);
+               }
+               
+               /* we should do at least one step */
+               if (arraylen == i)
+                       arraylen++;
+               
+               /* for each possible index, perform operation 
+                *      - assume that arraylen is greater than index
+                */
+               for (; i < arraylen; i++) {
+                       /* action to take depends on mode */
+                       if (mode == MODIFYKEY_MODE_INSERT)
+                               success += insert_keyframe(ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2);
+                       else if (mode == MODIFYKEY_MODE_DELETE)
+                               success += delete_keyframe(ksp->id, act, groupname, ksp->rna_path, i, cfra, kflag2);
+               }
+               
+               /* set recalc-flags */
+               if (ksp->id) {
+                       switch (GS(ksp->id->name)) {
+                               case ID_OB: /* Object (or Object-Related) Keyframes */
                                {
-                                       /* add property stored in KeyingSet Path */
-                                       if (BLI_dynstr_get_len(pathds))
-                                               BLI_dynstr_append(pathds, ".");
-                                               
-                                       /* apply some further templates? */
-                                       if (ksp->templates & KSP_TEMPLATE_ROT) {
-                                               /* for builtin Keying Sets, this template makes the best fitting path for the 
-                                                * current rotation mode of the Object / PoseChannel to be used
-                                                */
-                                               if (strcmp(ksp->rna_path, "rotation")==0) {
-                                                       /* get rotation mode */
-                                                       short rotmode= (cks->pchan)? (cks->pchan->rotmode) : 
-                                                                                  (GS(cks->id->name)==ID_OB)? ( ((Object *)cks->id)->rotmode ) :
-                                                                                  (0);
-                                                       
-                                                       /* determine path to build */
-                                                       if (rotmode == ROT_MODE_QUAT)
-                                                               BLI_dynstr_append(pathds, "rotation_quaternion");
-                                                       else if (rotmode == ROT_MODE_AXISANGLE)
-                                                               BLI_dynstr_append(pathds, "rotation_axis_angle");
-                                                       else
-                                                               BLI_dynstr_append(pathds, "rotation_euler");
-                                               }
-                                       }
-                                       else {
-                                               /* just directly use the path */
-                                               BLI_dynstr_append(pathds, ksp->rna_path);
-                                       }
-                                       
-                                       /* convert to C-string */
-                                       path= BLI_dynstr_get_cstring(pathds);
-                                       BLI_dynstr_free(pathds);
-                               }
-                               
-                               /* get pointer to name of group to add channels to 
-                                *      - KSP_GROUP_TEMPLATE_ITEM is handled above while constructing the paths 
-                                */
-                               if (ksp->groupmode == KSP_GROUP_NONE)
-                                       groupname= NULL;
-                               else if (ksp->groupmode == KSP_GROUP_KSNAME)
-                                       groupname= ks->name;
-                               else if (ksp->groupmode == KSP_GROUP_NAMED)
-                                       groupname= ksp->group;
-                               
-                               /* init arraylen and i - arraylen should be greater than i so that
-                                * normal non-array entries get keyframed correctly
-                                */
-                               i= ksp->array_index;
-                               arraylen= i+1;
-                               
-                               /* get length of array if whole array option is enabled */
-                               if (ksp->flag & KSP_FLAG_WHOLE_ARRAY) {
-                                       PointerRNA id_ptr, ptr;
-                                       PropertyRNA *prop;
+                                       Object *ob= (Object *)ksp->id;
                                        
-                                       RNA_id_pointer_create(cks->id, &id_ptr);
-                                       if (RNA_path_resolve(&id_ptr, path, &ptr, &prop) && prop)
-                                               arraylen= RNA_property_array_length(&ptr, prop);
-                               }
-                               
-                               /* for each possible index, perform operation 
-                                *      - assume that arraylen is greater than index
-                                */
-                               for (; i < arraylen; i++) {
-                                       /* action to take depends on mode */
-                                       if (mode == MODIFYKEY_MODE_INSERT)
-                                               success+= insert_keyframe(cks->id, act, groupname, path, i, cfra, kflag);
-                                       else if (mode == MODIFYKEY_MODE_DELETE)
-                                               success+= delete_keyframe(cks->id, act, groupname, path, i, cfra, kflag);
+                                       ob->recalc |= OB_RECALC;
                                }
-                               
-                               /* free the path */
-                               MEM_freeN(path);
+                                       break;
                        }
                        
-                       /* set recalc-flags */
-                       if (cks->id) {
-                               switch (GS(cks->id->name)) {
-                                       case ID_OB: /* Object (or Object-Related) Keyframes */
-                                       {
-                                               Object *ob= (Object *)cks->id;
-                                               
-                                               ob->recalc |= OB_RECALC;
-                                       }
-                                               break;
-                               }
-                               
-                               /* send notifiers for updates (this doesn't require context to work!) */
-                               WM_main_add_notifier(NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
-                       }
+                       /* send notifiers for updates (this doesn't require context to work!) */
+                       WM_main_add_notifier(NC_ANIMATION|ND_KEYFRAME_EDIT, NULL);
                }
        }
        
index 4a3ef38daa63aeb6a644434d8d061bb5665ec0a8..3f26a146c539d1a2ec7af5fad89ed78350d3f55c 100644 (file)
@@ -4867,12 +4867,7 @@ static int pose_clear_scale_exec(bContext *C, wmOperator *op)
        Object *ob= CTX_data_active_object(C);
        
        KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Scaling");
-       bCommonKeySrc cks;
-       ListBase dsources = {&cks, &cks};
-       
-       /* init common-key-source for use by KeyingSets */
-       memset(&cks, 0, sizeof(bCommonKeySrc));
-       cks.id= &ob->id;
+       short autokey = 0;
        
        /* only clear those channels that are not locked */
        CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) {
@@ -4885,13 +4880,12 @@ static int pose_clear_scale_exec(bContext *C, wmOperator *op)
                        
                /* do auto-keyframing as appropriate */
                if (autokeyframe_cfra_can_key(scene, &ob->id)) {
-                       /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
-                       cks.pchan= pchan;
-                       modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
-                       
                        /* clear any unkeyed tags */
                        if (pchan->bone)
                                pchan->bone->flag &= ~BONE_UNKEYED;
+                               
+                       /* tag for autokeying later */
+                       autokey = 1;
                }
                else {
                        /* add unkeyed tags */
@@ -4901,6 +4895,16 @@ static int pose_clear_scale_exec(bContext *C, wmOperator *op)
        }
        CTX_DATA_END;
        
+       /* perform autokeying on the bones if needed */
+       if (autokey) {
+               /* insert keyframes */
+               ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+               
+               /* now recalculate paths */
+               if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS))
+                       ED_pose_recalculate_paths(C, scene, ob);
+       }
+       
        DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
 
        /* note, notifier might evolve */
@@ -4930,12 +4934,7 @@ static int pose_clear_loc_exec(bContext *C, wmOperator *op)
        Object *ob= CTX_data_active_object(C);
        
        KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Location");
-       bCommonKeySrc cks;
-       ListBase dsources = {&cks, &cks};
-       
-       /* init common-key-source for use by KeyingSets */
-       memset(&cks, 0, sizeof(bCommonKeySrc));
-       cks.id= &ob->id;
+       short autokey = 0;
        
        /* only clear those channels that are not locked */
        CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) {
@@ -4949,13 +4948,12 @@ static int pose_clear_loc_exec(bContext *C, wmOperator *op)
                        
                /* do auto-keyframing as appropriate */
                if (autokeyframe_cfra_can_key(scene, &ob->id)) {
-                       /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
-                       cks.pchan= pchan;
-                       modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
-                       
                        /* clear any unkeyed tags */
                        if (pchan->bone)
                                pchan->bone->flag &= ~BONE_UNKEYED;
+                               
+                       /* tag for autokeying later */
+                       autokey = 1;
                }
                else {
                        /* add unkeyed tags */
@@ -4965,6 +4963,16 @@ static int pose_clear_loc_exec(bContext *C, wmOperator *op)
        }
        CTX_DATA_END;
        
+       /* perform autokeying on the bones if needed */
+       if (autokey) {
+               /* insert keyframes */
+               ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+               
+               /* now recalculate paths */
+               if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS))
+                       ED_pose_recalculate_paths(C, scene, ob);
+       }
+       
        DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
 
        /* note, notifier might evolve */
@@ -4994,12 +5002,7 @@ static int pose_clear_rot_exec(bContext *C, wmOperator *op)
        Object *ob= CTX_data_active_object(C);
        
        KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation");
-       bCommonKeySrc cks;
-       ListBase dsources = {&cks, &cks};
-       
-       /* init common-key-source for use by KeyingSets */
-       memset(&cks, 0, sizeof(bCommonKeySrc));
-       cks.id= &ob->id;
+       short autokey = 0;
        
        /* only clear those channels that are not locked */
        CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones) {
@@ -5097,13 +5100,12 @@ static int pose_clear_rot_exec(bContext *C, wmOperator *op)
                
                /* do auto-keyframing as appropriate */
                if (autokeyframe_cfra_can_key(scene, &ob->id)) {
-                       /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
-                       cks.pchan= pchan;
-                       modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
-                       
                        /* clear any unkeyed tags */
                        if (pchan->bone)
                                pchan->bone->flag &= ~BONE_UNKEYED;
+                               
+                       /* tag for autokeying later */
+                       autokey = 1;
                }
                else {
                        /* add unkeyed tags */
@@ -5113,6 +5115,16 @@ static int pose_clear_rot_exec(bContext *C, wmOperator *op)
        }
        CTX_DATA_END;
        
+       /* perform autokeying on the bones if needed */
+       if (autokey) {
+               /* insert keyframes */
+               ANIM_apply_keyingset(C, NULL, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+               
+               /* now recalculate paths */
+               if ((ob->pose->avs.path_bakeflag & MOTIONPATH_BAKE_HAS_PATHS))
+                       ED_pose_recalculate_paths(C, scene, ob);
+       }
+       
        DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
 
        /* note, notifier might evolve */
index e2fc2bd4088dd3b80565f03024e45aabe9d9e9cf..ecc84aaf4bbdb256e5a6b2cda3f5a927af98bb1d 100644 (file)
@@ -229,27 +229,28 @@ void poseAnim_mapping_autoKeyframe (bContext *C, Scene *scene, Object *ob, ListB
        
        /* insert keyframes as necessary if autokeyframing */
        if (autokeyframe_cfra_can_key(scene, &ob->id)) {
-               bCommonKeySrc cks;
-               ListBase dsources = {&cks, &cks};
                tPChanFCurveLink *pfl;
                
-               /* init common-key-source for use by KeyingSets */
-               memset(&cks, 0, sizeof(bCommonKeySrc));
-               cks.id= &ob->id;
-               
                /* iterate over each pose-channel affected, applying the changes */
                for (pfl= pfLinks->first; pfl; pfl= pfl->next) {
+                       ListBase dsources = {NULL, NULL};
                        bPoseChannel *pchan= pfl->pchan;
-                       /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
-                       cks.pchan= pchan;
                        
-                       /* insert keyframes */
+                       /* add datasource override for the PoseChannel so KeyingSet will do right thing */
+                       ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan); 
+                       
+                       /* insert keyframes 
+                        *      - these keyingsets here use dsources, since we need to specify exactly which keyframes get affected
+                        */
                        if (pchan->flag & POSE_LOC)
-                               modify_keyframes(scene, &dsources, NULL, ks_loc, MODIFYKEY_MODE_INSERT, cframe);
+                               ANIM_apply_keyingset(C, &dsources, NULL, ks_loc, MODIFYKEY_MODE_INSERT, cframe);
                        if (pchan->flag & POSE_ROT)
-                               modify_keyframes(scene, &dsources, NULL, ks_rot, MODIFYKEY_MODE_INSERT, cframe);
+                               ANIM_apply_keyingset(C, &dsources, NULL, ks_rot, MODIFYKEY_MODE_INSERT, cframe);
                        if (pchan->flag & POSE_SIZE)
-                               modify_keyframes(scene, &dsources, NULL, ks_scale, MODIFYKEY_MODE_INSERT, cframe);
+                               ANIM_apply_keyingset(C, &dsources, NULL, ks_scale, MODIFYKEY_MODE_INSERT, cframe);
+                               
+                       /* free the temp info */
+                       BLI_freelistN(&dsources);
                }
        }
 }
index 02194035ee9f22558f46d87cbc744380f46262fa..8d38d0530ce12cf15ce43695ab6233f140a39d65 100644 (file)
@@ -331,19 +331,14 @@ static int poselib_add_menu_invoke (bContext *C, wmOperator *op, wmEvent *evt)
 
 static int poselib_add_exec (bContext *C, wmOperator *op)
 {
-       Scene *scene= CTX_data_scene(C);
        Object *ob= CTX_data_active_object(C);
        bAction *act = poselib_validate(ob);
        bArmature *arm= (ob) ? ob->data : NULL;
        bPose *pose= (ob) ? ob->pose : NULL;
-       bPoseChannel *pchan;
        TimeMarker *marker;
        int frame= RNA_int_get(op->ptr, "frame");
        char name[64];
        
-       bCommonKeySrc cks;
-       ListBase dsources = {&cks, &cks};
-       
        /* sanity check (invoke should have checked this anyway) */
        if (ELEM3(NULL, ob, arm, pose)) 
                return OPERATOR_CANCELLED;
@@ -373,25 +368,12 @@ static int poselib_add_exec (bContext *C, wmOperator *op)
        /* validate name */
        BLI_uniquename(&act->markers, marker, "Pose", '.', offsetof(TimeMarker, name), sizeof(marker->name));
        
-       /* init common-key-source for use by KeyingSets */
-       memset(&cks, 0, sizeof(bCommonKeySrc));
-       cks.id= &ob->id;
-       
-       /* loop through selected posechannels, keying their pose to the action */
-       for (pchan= pose->chanbase.first; pchan; pchan= pchan->next) {
-               /* check if available */
-               if ((pchan->bone) && (arm->layer & pchan->bone->layer)) {
-                       if (pchan->bone->flag & BONE_SELECTED || pchan->bone==arm->act_bone) {
-                               /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
-                               cks.pchan= pchan;
-                               
-                               /* KeyingSet to use depends on rotation mode (but that's handled by the templates code)  */
-                               if (poselib_ks_locrotscale == NULL)
-                                       poselib_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale");
-                               modify_keyframes(scene, &dsources, act, poselib_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)frame);
-                       }
-               }
-       }
+       /* KeyingSet to use depends on rotation mode (but that's handled by the templates code)  */
+       if (poselib_ks_locrotscale == NULL)
+               poselib_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale");
+               
+       /* make the keyingset use context info to determine where to add keyframes */
+       ANIM_apply_keyingset(C, NULL, act, poselib_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)frame);
        
        /* store new 'active' pose number */
        act->active_marker= BLI_countlist(&act->markers);
@@ -784,13 +766,6 @@ static void poselib_keytag_pose (bContext *C, Scene *scene, tPoseLib_PreviewData
        bAction *act= pld->act;
        bActionGroup *agrp;
        
-       bCommonKeySrc cks;
-       ListBase dsources = {&cks, &cks};
-       
-       /* init common-key-source for use by KeyingSets */
-       memset(&cks, 0, sizeof(bCommonKeySrc));
-       cks.id= &pld->ob->id;
-       
        /* start tagging/keying */
        for (agrp= act->groups.first; agrp; agrp= agrp->next) {
                /* only for selected action channels */
@@ -798,21 +773,23 @@ static void poselib_keytag_pose (bContext *C, Scene *scene, tPoseLib_PreviewData
                        pchan= get_pose_channel(pose, agrp->name);
                        
                        if (pchan) {
-                               // TODO: use a standard autokeying function in future (to allow autokeying-editkeys to work)
-                               if (IS_AUTOKEY_MODE(scene, NORMAL)) {
-                                       /* Set keys on pose
-                                        *      - KeyingSet to use depends on rotation mode 
-                                        *      (but that's handled by the templates code)  
-                                        */
+                               if (autokeyframe_cfra_can_key(scene, &pld->ob->id)) {
+                                       ListBase dsources = {NULL, NULL};
+                                       
+                                       /* get KeyingSet to use */
                                        // TODO: for getting the KeyingSet used, we should really check which channels were affected
+                                       // TODO: this should get modified so that custom props are taken into account too!
                                        if (poselib_ks_locrotscale == NULL)
                                                poselib_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale");
                                        
-                                       /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
-                                       cks.pchan= pchan;
-                                       
-                                       /* now insert the keyframe */
-                                       modify_keyframes(scene, &dsources, NULL, poselib_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA);
+                                       /* now insert the keyframe(s) using the Keying Set
+                                        *      1) add datasource override for the PoseChannel
+                                        *      2) insert keyframes
+                                        *      3) free the extra info 
+                                        */
+                                       ANIM_relative_keyingset_add_source(&dsources, &pld->ob->id, &RNA_PoseBone, pchan); 
+                                       ANIM_apply_keyingset(C, &dsources, NULL, poselib_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA);
+                                       BLI_freelistN(&dsources);
                                        
                                        /* clear any unkeyed tags */
                                        if (pchan->bone)
index a162c8eb21a11481a44a6c01d78cde820f30e1e6..f20c79da17ec98c6f7fcace58ef501ac33e2499e 100644 (file)
@@ -849,14 +849,14 @@ void free_posebuf(void)
 {
        if (g_posebuf) {
                bPoseChannel *pchan;
-
+               
                for (pchan= g_posebuf->chanbase.first; pchan; pchan= pchan->next) {
                        if(pchan->prop) {
                                IDP_FreeProperty(pchan->prop);
                                MEM_freeN(pchan->prop);
                        }
                }
-
+               
                /* was copied without constraints */
                BLI_freelistN(&g_posebuf->chanbase);
                MEM_freeN(g_posebuf);
@@ -908,9 +908,6 @@ void POSE_OT_copy (wmOperatorType *ot)
 /* Pointers to the builtin KeyingSets that we want to use */
 static KeyingSet *posePaste_ks_locrotscale = NULL;             /* the only keyingset we'll need */
 
-/* transform.h */
-extern void autokeyframe_pose_cb_func(struct bContext *C, struct Scene *scene, struct View3D *v3d, struct Object *ob, int tmode, short targetless_ik);
-
 static int pose_paste_exec (bContext *C, wmOperator *op)
 {
        Scene *scene= CTX_data_scene(C);
@@ -919,13 +916,6 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
        char name[32];
        int flip= RNA_boolean_get(op->ptr, "flipped");
        
-       bCommonKeySrc cks;
-       ListBase dsources = {&cks, &cks};
-       
-       /* init common-key-source for use by KeyingSets */
-       memset(&cks, 0, sizeof(bCommonKeySrc));
-       cks.id= &ob->id;
-       
        /* sanity checks */
        if ELEM(NULL, ob, ob->pose)
                return OPERATOR_CANCELLED;
@@ -974,14 +964,14 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
                                else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
                                        /* quat/euler to axis angle */
                                        if (chan->rotmode > 0)
-                                               eulO_to_axis_angle( pchan->rotAxis, &pchan->rotAngle,chan->eul, chan->rotmode);
+                                               eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->eul, chan->rotmode);
                                        else    
-                                               quat_to_axis_angle( pchan->rotAxis, &pchan->rotAngle,chan->quat);
+                                               quat_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, chan->quat);
                                }
                                else {
                                        /* euler/axis-angle to quat */
                                        if (chan->rotmode > 0)
-                                               eulO_to_quat( pchan->quat,chan->eul, chan->rotmode);
+                                               eulO_to_quat(pchan->quat, chan->eul, chan->rotmode);
                                        else
                                                axis_angle_to_quat(pchan->quat, chan->rotAxis, pchan->rotAngle);
                                }
@@ -998,10 +988,10 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
                                        else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
                                                float eul[3];
                                                
-                                               axis_angle_to_eulO( eul, EULER_ORDER_DEFAULT,pchan->rotAxis, pchan->rotAngle);
+                                               axis_angle_to_eulO(eul, EULER_ORDER_DEFAULT, pchan->rotAxis, pchan->rotAngle);
                                                eul[1]*= -1;
                                                eul[2]*= -1;
-                                               eulO_to_axis_angle( pchan->rotAxis, &pchan->rotAngle,eul, EULER_ORDER_DEFAULT);
+                                               eulO_to_axis_angle(pchan->rotAxis, &pchan->rotAngle, eul, EULER_ORDER_DEFAULT);
                                                
                                                // experimental method (uncomment to test):
 #if 0
@@ -1013,62 +1003,55 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
                                        else {
                                                float eul[3];
                                                
-                                               quat_to_eul( eul,pchan->quat);
+                                               quat_to_eul(eul, pchan->quat);
                                                eul[1]*= -1;
                                                eul[2]*= -1;
-                                               eul_to_quat( pchan->quat,eul);
+                                               eul_to_quat(pchan->quat, eul);
                                        }
                                }
                                
                                /* ID property */
-                               if(pchan->prop) {
+                               if (pchan->prop) {
                                        IDP_FreeProperty(pchan->prop);
                                        MEM_freeN(pchan->prop);
                                        pchan->prop= NULL;
                                }
-
-                               if(chan->prop) {
+                               
+                               if (chan->prop)
                                        pchan->prop= IDP_CopyProperty(chan->prop);
+                               
+                               /* keyframing tagging */
+                               if (autokeyframe_cfra_can_key(scene, &ob->id)) {        
+                                       ListBase dsources = {NULL, NULL};
+                                       
+                                       /* get KeyingSet to use */
+                                       // TODO: for getting the KeyingSet used, we should really check which channels were affected
+                                       // TODO: this should get modified so that custom props are taken into account too!
+                                       if (posePaste_ks_locrotscale == NULL)
+                                               posePaste_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale");
+                                       
+                                       /* now insert the keyframe(s) using the Keying Set
+                                        *      1) add datasource override for the PoseChannel
+                                        *      2) insert keyframes
+                                        *      3) free the extra info 
+                                        */
+                                       ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan); 
+                                       ANIM_apply_keyingset(C, &dsources, NULL, posePaste_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA);
+                                       BLI_freelistN(&dsources);
+                                       
+                                       /* clear any unkeyed tags */
+                                       if (chan->bone)
+                                               chan->bone->flag &= ~BONE_UNKEYED;
                                }
-
-                               /* auto key, TODO, fix up this INSERTAVAIL vs all other cases */
-                               if (IS_AUTOKEY_FLAG(INSERTAVAIL) == 0) { /* deal with this case later */
-                                       if (autokeyframe_cfra_can_key(scene, &ob->id)) {
-
-                                               /* Set keys on pose
-                                                *      - KeyingSet to use depends on rotation mode
-                                                *      (but that's handled by the templates code)
-                                                */
-                                               // TODO: for getting the KeyingSet used, we should really check which channels were affected
-                                               if (posePaste_ks_locrotscale == NULL)
-                                                       posePaste_ks_locrotscale= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale");
-
-                                               /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
-                                               cks.pchan= pchan;
-
-                                               modify_keyframes(scene, &dsources, NULL, posePaste_ks_locrotscale, MODIFYKEY_MODE_INSERT, (float)CFRA);
-
-                                               /* clear any unkeyed tags */
-                                               if (chan->bone)
-                                                       chan->bone->flag &= ~BONE_UNKEYED;
-                                       }
-                                       else {
-                                               /* add unkeyed tags */
-                                               if (chan->bone)
-                                                       chan->bone->flag |= BONE_UNKEYED;
-                                       }
+                               else {
+                                       /* add unkeyed tags */
+                                       if (chan->bone)
+                                               chan->bone->flag |= BONE_UNKEYED;
                                }
                        }
                }
        }
-
-       if (IS_AUTOKEY_FLAG(INSERTAVAIL)) {
-               View3D *v3d= CTX_wm_view3d(C);
-               autokeyframe_pose_cb_func(C, scene, v3d, ob, TFM_TRANSLATION, 0);
-               autokeyframe_pose_cb_func(C, scene, v3d, ob, TFM_ROTATION, 0);
-               autokeyframe_pose_cb_func(C, scene, v3d, ob, TFM_TIME_SCALE, 0);
-       }
-
+       
        /* Update event for pose and deformation children */
        DAG_id_flush_update(&ob->id, OB_RECALC_DATA);
        
@@ -1077,13 +1060,13 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
        }
        else {
                /* need to trick depgraph, action is not allowed to execute on pose */
+               // XXX: this is probably not an issue anymore
                where_is_pose(scene, ob);
                ob->recalc= 0;
        }
        
        /* notifiers for updates */
        WM_event_add_notifier(C, NC_OBJECT|ND_POSE, ob);
-       WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_EDIT, NULL); // XXX not really needed, but here for completeness...
 
        return OPERATOR_FINISHED;
 }
@@ -1754,13 +1737,7 @@ static int pose_flip_quats_exec (bContext *C, wmOperator *op)
 {
        Scene *scene= CTX_data_scene(C);
        Object *ob= CTX_data_active_object(C);
-       
-       bCommonKeySrc cks;
-       ListBase dsources = {&cks, &cks};
-       
-       /* init common-key-source for use by KeyingSets */
-       memset(&cks, 0, sizeof(bCommonKeySrc));
-       cks.id= &ob->id;
+       KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, "LocRotScale");
        
        /* loop through all selected pchans, flipping and keying (as needed) */
        CTX_DATA_BEGIN(C, bPoseChannel*, pchan, selected_pose_bones)
@@ -1773,20 +1750,18 @@ static int pose_flip_quats_exec (bContext *C, wmOperator *op)
                        pchan->quat[2]= -pchan->quat[2];
                        pchan->quat[3]= -pchan->quat[3];
                        
-                       /* perform auto-keying 
-                        * NOTE: paths don't need recalculation here, since the orientations shouldn't have changed
-                        */
+                       /* tagging */
                        if (autokeyframe_cfra_can_key(scene, &ob->id)) {
-                               /* Set keys on pose
-                                *      - KeyingSet to use depends on rotation mode 
-                                *      (but that's handled by the templates code)  
-                                */
-                               KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation");
+                               ListBase dsources = {NULL, NULL};
                                
-                               /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
-                               cks.pchan= pchan;
-                               
-                               modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+                               /* now insert the keyframe(s) using the Keying Set
+                                *      1) add datasource override for the PoseChannel
+                                *      2) insert keyframes
+                                *      3) free the extra info 
+                                */
+                               ANIM_relative_keyingset_add_source(&dsources, &ob->id, &RNA_PoseBone, pchan); 
+                               ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+                               BLI_freelistN(&dsources);
                                
                                /* clear any unkeyed tags */
                                if (pchan->bone)
index 2c58d9e3ff5166f7ce410d3b4bc8022a28ed7633..576069d78e8915a16fa737323b84ce0c239e1392 100644 (file)
@@ -89,8 +89,6 @@ int insert_vert_fcurve(struct FCurve *fcu, float x, float y, short flag);
  */
 short insert_keyframe_direct(struct PointerRNA ptr, struct PropertyRNA *prop, struct FCurve *fcu, float cfra, short flag);
 
-
-
 /* -------- */
 
 /* Main Keyframing API calls: 
@@ -106,48 +104,92 @@ short delete_keyframe(struct ID *id, struct bAction *act, const char group[], co
 
 /* ************ Keying Sets ********************** */
 
-/* temporary struct to gather data combos to keyframe
- * (is used by modify_keyframes for 'relative' KeyingSets, provided via the dsources arg)
- */
-typedef struct bCommonKeySrc {
-       struct bCommonKeySrc *next, *prev;
-               
-               /* general data/destination-source settings */
-       struct ID *id;                                  /* id-block this comes from */
+/* forward decl. for this struct which is declared a bit later... */
+struct KeyingSetInfo;
+
+/* Polling Callback for KeyingSets */
+typedef int (*cbKeyingSet_Poll)(struct KeyingSetInfo *ksi, struct bContext *C);
+/* Context Iterator Callback for KeyingSets */
+typedef void (*cbKeyingSet_Iterator)(struct KeyingSetInfo *ksi, struct bContext *C, struct KeyingSet *ks);
+/* Property Specifier Callback for KeyingSets (called from iterators) */
+typedef void (*cbKeyingSet_Generate)(struct KeyingSetInfo *ksi, struct bContext *C, struct KeyingSet *ks, struct PointerRNA *ptr); 
+
+
+/* Callback info for 'Procedural' KeyingSets to use */
+typedef struct KeyingSetInfo {
+       struct KeyingSetInfo *next, *prev;
+       
+       /* info */
+               /* identifier so that user can hook this up to a KeyingSet */
+       char name[64];
+               /* keying settings */
+       short keyingflag;
+               /* builtin? */
+       short builtin;
+       
+       /* polling callbacks */
+               /* callback for polling the context for whether the right data is available */
+       cbKeyingSet_Poll poll;
        
-               /* specific cases */
-       struct bPoseChannel *pchan;     
-       struct bConstraint *con;
-} bCommonKeySrc;
+       /* generate callbacks */
+               /* iterator to use to go through collections of data in context
+                *      - this callback is separate from the 'adding' stage, allowing 
+                *        BuiltIn KeyingSets to be manually specified to use 
+                */
+       cbKeyingSet_Iterator iter;
+               /* generator to use to add properties based on the data found by iterator */
+       cbKeyingSet_Generate generate;
+       
+       /* RNA integration */
+       ExtensionRNA ext;
+} KeyingSetInfo;
 
 /* -------- */
 
+/* Add another data source for Relative Keying Sets to be evaluated with */
+void ANIM_relative_keyingset_add_source(ListBase *dsources, struct ID *id, struct StructRNA *srna, void *data);
+
+
 /* mode for modify_keyframes */
 typedef enum eModifyKey_Modes {
        MODIFYKEY_MODE_INSERT = 0,
        MODIFYKEY_MODE_DELETE,
 } eModifyKey_Modes;
 
-/* Keyframing Helper Call - use the provided Keying Set to Add/Remove Keyframes */
-int modify_keyframes(struct Scene *scene, struct ListBase *dsources, struct bAction *act, struct KeyingSet *ks, short mode, float cfra);
+/* return codes for errors (with Relative KeyingSets) */
+typedef enum eModifyKey_Returns {
+               /* context info was invalid for using the Keying Set */
+       MODIFYKEY_INVALID_CONTEXT = -1,
+               /* there isn't any typeinfo for generating paths from context */
+       MODIFYKEY_MISSING_TYPEINFO = -2,
+} eModifyKey_Returns;
 
-/* -------- */
+/* use the specified KeyingSet to add/remove various Keyframes on the specified frame */
+int ANIM_apply_keyingset(struct bContext *C, ListBase *dsources, struct bAction *act, struct KeyingSet *ks, short mode, float cfra);
 
-/* Generate menu of KeyingSets */
-char *ANIM_build_keyingsets_menu(struct ListBase *list, short for_edit);
+/* -------- */
 
 /* Get the first builtin KeyingSet with the given name, which occurs after the given one (or start of list if none given) */
-struct KeyingSet *ANIM_builtin_keyingset_get_named(struct KeyingSet *prevKS, char name[]);
+struct KeyingSet *ANIM_builtin_keyingset_get_named(struct KeyingSet *prevKS, const char name[]);
+
+/* Find KeyingSet type info given a name */
+KeyingSetInfo *ANIM_keyingset_info_find_named(const char name[]);
 
-/* Initialise builtin KeyingSets on startup */
-void init_builtin_keyingsets(void);
+/* for RNA type registrations... */
+void ANIM_keyingset_info_register(const struct bContext *C, KeyingSetInfo *ksi);
+void ANIM_keyingset_info_unregister(const struct bContext *C, KeyingSetInfo *ksi);
 
+/* cleanup on exit */
+void ANIM_keyingset_infos_exit(void);
 
 /* -------- */
 
 /* Get the active KeyingSet for the given scene */
 struct KeyingSet *ANIM_scene_get_active_keyingset(struct Scene *scene);
 
+/* Check if KeyingSet can be used in the current context */
+short ANIM_keyingset_context_ok_poll(struct bContext *C, struct KeyingSet *ks);
+
 /* ************ Drivers ********************** */
 
 /* Returns whether there is a driver in the copy/paste buffer to paste */
index 30df347bc607c6e0ec8a5bac0f6b238b6015af33..db15322bbc4f90cc53a9402262be78b037921714 100644 (file)
 
 static int object_location_clear_exec(bContext *C, wmOperator *op)
 {
-       Scene *scene= CTX_data_scene(C);
-       
+       Scene *scene = CTX_data_scene(C);
        KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Location");
-       bCommonKeySrc cks;
-       ListBase dsources = {&cks, &cks};
-       
-       /* init common-key-source for use by KeyingSets */
-       memset(&cks, 0, sizeof(bCommonKeySrc));
        
        /* clear location of selected objects if not in weight-paint mode */
        CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
-               if(!(ob->mode & OB_MODE_WEIGHT_PAINT)) {
-                       if((ob->protectflag & OB_LOCK_LOCX)==0)
+               if (!(ob->mode & OB_MODE_WEIGHT_PAINT)) {
+                       /* clear location if not locked */
+                       if ((ob->protectflag & OB_LOCK_LOCX)==0)
                                ob->loc[0]= ob->dloc[0]= 0.0f;
-                       if((ob->protectflag & OB_LOCK_LOCY)==0)
+                       if ((ob->protectflag & OB_LOCK_LOCY)==0)
                                ob->loc[1]= ob->dloc[1]= 0.0f;
-                       if((ob->protectflag & OB_LOCK_LOCZ)==0)
+                       if ((ob->protectflag & OB_LOCK_LOCZ)==0)
                                ob->loc[2]= ob->dloc[2]= 0.0f;
                                
-                       /* do auto-keyframing as appropriate */
+                       /* auto keyframing */
                        if (autokeyframe_cfra_can_key(scene, &ob->id)) {
-                               /* init cks for this object, then use the relative KeyingSets to keyframe it */
-                               cks.id= &ob->id;
-                               modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+                               ListBase dsources = {NULL, NULL};
+                               
+                               /* now insert the keyframe(s) using the Keying Set
+                                *      1) add datasource override for the PoseChannel
+                                *      2) insert keyframes
+                                *      3) free the extra info 
+                                */
+                               ANIM_relative_keyingset_add_source(&dsources, &ob->id, NULL, NULL); 
+                               ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+                               BLI_freelistN(&dsources);
                        }
                }
+               
                ob->recalc |= OB_RECALC_OB;
        }
        CTX_DATA_END;
@@ -131,17 +134,12 @@ void OBJECT_OT_location_clear(wmOperatorType *ot)
 static int object_rotation_clear_exec(bContext *C, wmOperator *op)
 {
        Scene *scene= CTX_data_scene(C);
-       
        KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation");
-       bCommonKeySrc cks;
-       ListBase dsources = {&cks, &cks};
-       
-       /* init common-key-source for use by KeyingSets */
-       memset(&cks, 0, sizeof(bCommonKeySrc));
        
        /* clear rotation of selected objects if not in weight-paint mode */
        CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
                if(!(ob->mode & OB_MODE_WEIGHT_PAINT)) {
+                       /* clear rotations that aren't locked */
                        if (ob->protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ|OB_LOCK_ROTW)) {
                                if (ob->protectflag & OB_LOCK_ROT4D) {
                                        /* perform clamping on a component by component basis */
@@ -233,13 +231,21 @@ static int object_rotation_clear_exec(bContext *C, wmOperator *op)
                                }
                        }
                        
-                       /* do auto-keyframing as appropriate */
+                       /* auto keyframing */
                        if (autokeyframe_cfra_can_key(scene, &ob->id)) {
-                               /* init cks for this object, then use the relative KeyingSets to keyframe it */
-                               cks.id= &ob->id;
-                               modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+                               ListBase dsources = {NULL, NULL};
+                               
+                               /* now insert the keyframe(s) using the Keying Set
+                                *      1) add datasource override for the PoseChannel
+                                *      2) insert keyframes
+                                *      3) free the extra info 
+                                */
+                               ANIM_relative_keyingset_add_source(&dsources, &ob->id, NULL, NULL); 
+                               ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+                               BLI_freelistN(&dsources);
                        }
                }
+               
                ob->recalc |= OB_RECALC_OB;
        }
        CTX_DATA_END;
@@ -270,35 +276,37 @@ void OBJECT_OT_rotation_clear(wmOperatorType *ot)
 static int object_scale_clear_exec(bContext *C, wmOperator *op)
 {
        Scene *scene= CTX_data_scene(C);
-       
        KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Scaling");
-       bCommonKeySrc cks;
-       ListBase dsources = {&cks, &cks};
-       
-       /* init common-key-source for use by KeyingSets */
-       memset(&cks, 0, sizeof(bCommonKeySrc));
        
        /* clear scales of selected objects if not in weight-paint mode */
        CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
                if(!(ob->mode & OB_MODE_WEIGHT_PAINT)) {
-                       if((ob->protectflag & OB_LOCK_SCALEX)==0) {
+                       /* clear scale factors which are not locked */
+                       if ((ob->protectflag & OB_LOCK_SCALEX)==0) {
                                ob->dsize[0]= 0.0f;
                                ob->size[0]= 1.0f;
                        }
-                       if((ob->protectflag & OB_LOCK_SCALEY)==0) {
+                       if ((ob->protectflag & OB_LOCK_SCALEY)==0) {
                                ob->dsize[1]= 0.0f;
                                ob->size[1]= 1.0f;
                        }
-                       if((ob->protectflag & OB_LOCK_SCALEZ)==0) {
+                       if ((ob->protectflag & OB_LOCK_SCALEZ)==0) {
                                ob->dsize[2]= 0.0f;
                                ob->size[2]= 1.0f;
                        }
                        
-                       /* do auto-keyframing as appropriate */
+                       /* auto keyframing */
                        if (autokeyframe_cfra_can_key(scene, &ob->id)) {
-                               /* init cks for this object, then use the relative KeyingSets to keyframe it */
-                               cks.id= &ob->id;
-                               modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+                               ListBase dsources = {NULL, NULL};
+                               
+                               /* now insert the keyframe(s) using the Keying Set
+                                *      1) add datasource override for the PoseChannel
+                                *      2) insert keyframes
+                                *      3) free the extra info 
+                                */
+                               ANIM_relative_keyingset_add_source(&dsources, &ob->id, NULL, NULL); 
+                               ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+                               BLI_freelistN(&dsources);
                        }
                }
                ob->recalc |= OB_RECALC_OB;
index 38a7163d35f7397288aeef3f128a4844ef94a807..828d536883499433834faef4eb8475fd5115bc98 100644 (file)
@@ -2323,7 +2323,7 @@ static void flyEvent(FlyInfo *fly, wmEvent *event)
        }
 }
 
-static int flyApply(FlyInfo *fly)
+static int flyApply(bContext *C, FlyInfo *fly)
 {
        /*
        fly mode - Shift+F
@@ -2606,13 +2606,10 @@ static int flyApply(FlyInfo *fly)
 
                                /* record the motion */
                                if (autokeyframe_cfra_can_key(scene, id_key)) {
-                                       bCommonKeySrc cks;
-                                       ListBase dsources = {&cks, &cks};
-                                       int cfra = CFRA;
+                                       ListBase dsources = {NULL, NULL};
                                        
-                                       /* init common-key-source for use by KeyingSets */
-                                       memset(&cks, 0, sizeof(bCommonKeySrc));
-                                       cks.id= id_key;
+                                       /* add datasource override for the camera object */
+                                       ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL); 
                                        
                                        /* insert keyframes 
                                         *      1) on the first frame
@@ -2621,12 +2618,15 @@ static int flyApply(FlyInfo *fly)
                                         */
                                        if (fly->xlock || fly->zlock || moffset[0] || moffset[1]) {
                                                KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation");
-                                               modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+                                               ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
                                        }
                                        if (fly->speed) {
                                                KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Location");
-                                               modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+                                               ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
                                        }
+                                       
+                                       /* free temp data */
+                                       BLI_freelistN(&dsources);
                                }
                        }
                } else
@@ -2689,7 +2689,7 @@ static int fly_modal(bContext *C, wmOperator *op, wmEvent *event)
        flyEvent(fly, event);
 
        if(event->type==TIMER && event->customdata == fly->timer)
-               flyApply(fly);
+               flyApply(C, fly);
 
        if(fly->redraw) {
                ED_region_tag_redraw(CTX_wm_region(C));
index 372aa42bac37ce9f9e898d992c2fb2153620936a..9c570e10406c1f5e6815ac2b370981035ae5d235 100644 (file)
 #include "BKE_report.h"
 #include "BKE_scene.h"
 
-//#include "BIF_editview.h"
-//#include "BIF_editlattice.h"
-//#include "BIF_editconstraint.h"
-//#include "BIF_editmesh.h"
-//#include "BIF_editsima.h"
-//#include "BIF_editparticle.h"
 #include "BIF_gl.h"
-//#include "BIF_poseobject.h"
-//#include "BIF_meshtools.h"
-//#include "BIF_mywindow.h"
-//#include "BIF_resources.h"
-//#include "BIF_screen.h"
-//#include "BIF_space.h"
-//#include "BIF_toolbox.h"
 
 #include "ED_anim_api.h"
 #include "ED_armature.h"
 
 #include "UI_view2d.h"
 
-//#include "BSE_edit.h"
-//#include "BDR_editobject.h"          // reset_slowparents()
-//#include "BDR_gpencil.h"
-
 #include "BLI_math.h"
 #include "BLI_blenlib.h"
 #include "BLI_editVert.h"
 
-//#include "editmesh.h"
-//
-//#include "blendef.h"
-//
-//#include "mydevice.h"
+#include "RNA_access.h"
 
 extern ListBase editelems;
 
@@ -4484,20 +4463,21 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
        // TODO: this should probably be done per channel instead...
        if (autokeyframe_cfra_can_key(scene, id)) {
                KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
-               bCommonKeySrc cks;
-               ListBase dsources = {&cks, &cks};
+               ListBase dsources = {NULL, NULL};
                float cfra= (float)CFRA; // xxx this will do for now
                short flag = 0;
                
-               /* init common-key-source for use by KeyingSets */
-               memset(&cks, 0, sizeof(bCommonKeySrc));
-               cks.id= &ob->id;
-               
+               /* get flags used for inserting keyframes */
                flag = ANIM_get_keyframing_flags(scene, 1);
                
+               /* add datasource override for the camera object */
+               ANIM_relative_keyingset_add_source(&dsources, id, NULL, NULL); 
+               
                if (IS_AUTOKEY_FLAG(ONLYKEYINGSET) && (active_ks)) {
-                       /* only insert into active keyingset */
-                       modify_keyframes(scene, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
+                       /* only insert into active keyingset 
+                        * NOTE: we assume here that the active Keying Set does not need to have its iterator overridden spe
+                        */
+                       ANIM_apply_keyingset(C, NULL, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
                }
                else if (IS_AUTOKEY_FLAG(INSERTAVAIL)) {
                        AnimData *adt= ob->adt;
@@ -4543,22 +4523,25 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
                        /* insert keyframes for the affected sets of channels using the builtin KeyingSets found */
                        if (doLoc) {
                                KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Location");
-                               modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+                               ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
                        }
                        if (doRot) {
                                KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation");
-                               modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+                               ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
                        }
                        if (doScale) {
                                KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Scale");
-                               modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+                               ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
                        }
                }
                /* insert keyframe in all (transform) channels */
                else {
                        KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale");
-                       modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+                       ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
                }
+               
+               /* free temp info */
+               BLI_freelistN(&dsources);
        }
 }
 
@@ -4579,15 +4562,9 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
        // TODO: this should probably be done per channel instead...
        if (autokeyframe_cfra_can_key(scene, id)) {
                KeyingSet *active_ks = ANIM_scene_get_active_keyingset(scene);
-               bCommonKeySrc cks;
-               ListBase dsources = {&cks, &cks};
                float cfra= (float)CFRA;
                short flag= 0;
                
-               /* init common-key-source for use by KeyingSets */
-               memset(&cks, 0, sizeof(bCommonKeySrc));
-               cks.id= &ob->id;
-               
                /* flag is initialised from UserPref keyframing settings
                 *      - special exception for targetless IK - INSERTKEY_MATRIX keyframes should get
                 *        visual keyframes even if flag not set, as it's not that useful otherwise
@@ -4600,14 +4577,18 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
                
                for (pchan=pose->chanbase.first; pchan; pchan=pchan->next) {
                        if (pchan->bone->flag & BONE_TRANSFORM) {
+                               ListBase dsources = {NULL, NULL};
+                               
                                /* clear any 'unkeyed' flag it may have */
                                pchan->bone->flag &= ~BONE_UNKEYED;
                                
+                               /* add datasource override for the camera object */
+                               ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan); 
+                               
                                /* only insert into active keyingset? */
+                               // TODO: move this first case out of the loop
                                if (IS_AUTOKEY_FLAG(ONLYKEYINGSET) && (active_ks)) {
-                                       /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
-                                       cks.pchan= pchan;
-                                       modify_keyframes(scene, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
+                                       ANIM_apply_keyingset(C, NULL, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
                                }
                                /* only insert into available channels? */
                                else if (IS_AUTOKEY_FLAG(INSERTAVAIL)) {
@@ -4656,34 +4637,25 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
                                        
                                        if (doLoc) {
                                                KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Location");
-                                               
-                                               /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
-                                               cks.pchan= pchan;
-                                               modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+                                               ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
                                        }
                                        if (doRot) {
                                                KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation");
-                                               
-                                               /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
-                                               cks.pchan= pchan;
-                                               modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+                                               ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
                                        }
                                        if (doScale) {
                                                KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Scale");
-                                               
-                                               /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
-                                               cks.pchan= pchan;
-                                               modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+                                               ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
                                        }
                                }
                                /* insert keyframe in all (transform) channels */
                                else {
                                        KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "LocRotScale");
-                                       
-                                       /* init cks for this PoseChannel, then use the relative KeyingSets to keyframe it */
-                                       cks.pchan= pchan;
-                                       modify_keyframes(scene, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
+                                       ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, cfra);
                                }
+                               
+                               /* free temp info */
+                               BLI_freelistN(&dsources);
                        }
                }
                
index d2755f71fa32f29aec8caea35d494c57e652bc67..8e46cfefba5997228b07d35d6b2219c9f4ff88ee 100644 (file)
@@ -663,20 +663,19 @@ typedef enum eNlaTrack_Flag {
 typedef struct KS_Path {
        struct KS_Path *next, *prev;
        
-               /* absolute paths only */
        ID *id;                                 /* ID block that keyframes are for */
        char group[64];                 /* name of the group to add to */
        
-               /* relative paths only */
        int idtype;                             /* ID-type that path can be used on */
-       int templates;                  /* Templates that will be encountered in the path (as set of bitflags) */
        
-               /* all paths */
+       short groupmode;                /* group naming (eKSP_Grouping) */
+       short pad;
+       
        char *rna_path;                 /* dynamically (or statically in the case of predefined sets) path */
        int array_index;                /* index that path affects */
        
        short flag;                             /* various settings, etc. */
-       short groupmode;                /* group naming (eKSP_Grouping) */
+       short keyingflag;               /* settings to supply insertkey() with */
 } KS_Path;
 
 /* KS_Path->flag */
@@ -734,6 +733,7 @@ typedef struct KeyingSet {
        ListBase paths;                 /* (KS_Path) paths to keyframe to */
        
        char name[64];                  /* user-viewable name for KeyingSet (for menus, etc.) */
+       char typeinfo[64];              /* name of the typeinfo data used for the relative paths */
        
        short flag;                             /* settings for KeyingSet */
        short keyingflag;               /* settings to supply insertkey() with */
index ae431beb1fe83504364dcdd46cc568615f427eea..e50b1b7ad5803e763608e6899eb71b329bca95c7 100644 (file)
@@ -257,6 +257,7 @@ extern StructRNA RNA_KeyConfig;
 extern StructRNA RNA_Keyframe;
 extern StructRNA RNA_KeyingSet;
 extern StructRNA RNA_KeyingSetPath;
+extern StructRNA RNA_KeyingSetInfo;
 extern StructRNA RNA_KeyMap;
 extern StructRNA RNA_KeyMapItem;
 extern StructRNA RNA_KinematicConstraint;
index 453d9b9a84401f3239a901bff00b9be1706b3bbe..e048a79daf86c0f8e344424073602a95beb7f48f 100644 (file)
 
 #include "MEM_guardedalloc.h"
 
+#include "ED_keyframing.h"
+
 /* exported for use in API */
 EnumPropertyItem keyingset_path_grouping_items[] = {
        {KSP_GROUP_NAMED, "NAMED", 0, "Named Group", ""},
        {KSP_GROUP_NONE, "NONE", 0, "None", ""},
        {KSP_GROUP_KSNAME, "KEYINGSET", 0, "Keying Set Name", ""},
-       {KSP_GROUP_TEMPLATE_ITEM, "TEMPLATE", 0, "Innermost Context-Item Name", ""},
        {0, NULL, 0, NULL, NULL}};
 
 #ifdef RNA_RUNTIME
@@ -66,6 +67,152 @@ static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value)
 
 /* ****************************** */
 
+/* wrapper for poll callback */
+static int RKS_POLL_rna_internal(KeyingSetInfo *ksi, bContext *C)
+{
+       PointerRNA ptr;
+       ParameterList list;
+       FunctionRNA *func;
+       void *ret;
+       int ok;
+
+       RNA_pointer_create(NULL, ksi->ext.srna, ksi, &ptr);
+       func= RNA_struct_find_function(&ptr, "poll");
+
+       RNA_parameter_list_create(&list, &ptr, func);
+               /* hook up arguments */
+               RNA_parameter_set_lookup(&list, "ksi", &ksi);
+               RNA_parameter_set_lookup(&list, "context", &C);
+               
+               /* execute the function */
+               ksi->ext.call(&ptr, func, &list);
+               
+               /* read the result */
+               RNA_parameter_get_lookup(&list, "ok", &ret);
+               ok= *(int*)ret;
+       RNA_parameter_list_free(&list);
+       
+       return ok;
+}
+
+/* wrapper for iterator callback */
+static void RKS_ITER_rna_internal(KeyingSetInfo *ksi, bContext *C, KeyingSet *ks)
+{
+       PointerRNA ptr;
+       ParameterList list;
+       FunctionRNA *func;
+
+       RNA_pointer_create(NULL, ksi->ext.srna, ksi, &ptr);
+       func= RNA_struct_find_function(&ptr, "iterator");
+
+       RNA_parameter_list_create(&list, &ptr, func);
+               /* hook up arguments */
+               RNA_parameter_set_lookup(&list, "ksi", &ksi);
+               RNA_parameter_set_lookup(&list, "context", &C);
+               RNA_parameter_set_lookup(&list, "ks", &ks);
+               
+               /* execute the function */
+               ksi->ext.call(&ptr, func, &list);
+       RNA_parameter_list_free(&list);
+}
+
+/* wrapper for generator callback */
+static void RKS_GEN_rna_internal(KeyingSetInfo *ksi, bContext *C, KeyingSet *ks, PointerRNA *data)
+{
+       PointerRNA ptr;
+       ParameterList list;
+       FunctionRNA *func;
+
+       RNA_pointer_create(NULL, ksi->ext.srna, ksi, &ptr);
+       func= RNA_struct_find_function(&ptr, "iterator");
+
+       RNA_parameter_list_create(&list, &ptr, func);
+               /* hook up arguments */
+               RNA_parameter_set_lookup(&list, "ksi", &ksi);
+               RNA_parameter_set_lookup(&list, "context", &C);
+               RNA_parameter_set_lookup(&list, "ks", &ks);
+               RNA_parameter_set_lookup(&list, "data", &data);
+               
+               /* execute the function */
+               ksi->ext.call(&ptr, func, &list);
+       RNA_parameter_list_free(&list);
+}
+
+/* ------ */
+
+// XXX: the exact purpose of this is not too clear... maybe we want to revise this at some point?
+static StructRNA *rna_KeyingSetInfo_refine(PointerRNA *ptr)
+{
+       KeyingSetInfo *ksi= (KeyingSetInfo *)ptr->data;
+       return (ksi->ext.srna)? ksi->ext.srna: &RNA_KeyingSetInfo;
+}
+
+static void rna_KeyingSetInfo_unregister(const bContext *C, StructRNA *type)
+{
+       KeyingSetInfo *ksi= RNA_struct_blender_type_get(type);
+
+       if (ksi == NULL)
+               return;
+       
+       /* free RNA data referencing this */
+       RNA_struct_free_extension(type, &ksi->ext);
+       RNA_struct_free(&BLENDER_RNA, type);
+       
+       /* unlink Blender-side data */
+       ANIM_keyingset_info_unregister(C, ksi);
+}
+
+static StructRNA *rna_KeyingSetInfo_register(const bContext *C, ReportList *reports, void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+{
+       KeyingSetInfo dummyksi = {0};
+       KeyingSetInfo *ksi;
+       PointerRNA dummyptr;
+       int have_function[3];
+
+       /* setup dummy type info to store static properties in */
+       // TODO: perhaps we want to get users to register as if they're using 'KeyingSet' directly instead?
+       RNA_pointer_create(NULL, &RNA_KeyingSetInfo, &dummyksi, &dummyptr);
+       
+       /* validate the python class */
+       if (validate(&dummyptr, data, have_function) != 0)
+               return NULL;
+       
+       if (strlen(identifier) >= sizeof(dummyksi.name)) {
+               BKE_reportf(reports, RPT_ERROR, "registering keying set info class: '%s' is too long, maximum length is %d.", identifier, sizeof(dummyksi.name));
+               return NULL;
+       }
+       
+       /* check if we have registered this info before, and remove it */
+       ksi = ANIM_keyingset_info_find_named(dummyksi.name);
+       if (ksi && ksi->ext.srna)
+               rna_KeyingSetInfo_unregister(C, ksi->ext.srna);
+       
+       /* create a new KeyingSetInfo type */
+       ksi= MEM_callocN(sizeof(KeyingSetInfo), "python keying set info");
+       memcpy(ksi, &dummyksi, sizeof(KeyingSetInfo));
+       
+       /* set RNA-extensions info */
+       ksi->ext.srna= RNA_def_struct(&BLENDER_RNA, ksi->name, "KeyingSetInfo"); 
+       ksi->ext.data= data;
+       ksi->ext.call= call;
+       ksi->ext.free= free;
+       RNA_struct_blender_type_set(ksi->ext.srna, ksi);
+       
+       /* set callbacks */
+       // NOTE: we really should have all of these... 
+       ksi->poll= (have_function[0])? RKS_POLL_rna_internal: NULL;
+       ksi->iter= (have_function[1])? RKS_ITER_rna_internal: NULL;
+       ksi->generate= (have_function[2])? RKS_GEN_rna_internal: NULL;
+
+       /* add and register with other info as needed */
+       ANIM_keyingset_info_register(C, ksi);
+       
+       /* return the struct-rna added */
+       return ksi->ext.srna;
+}
+
+/* ****************************** */
+
 static StructRNA *rna_ksPath_id_typef(PointerRNA *ptr)
 {
        KS_Path *ksp= (KS_Path*)ptr->data;
@@ -123,6 +270,14 @@ static void rna_ksPath_RnaPath_set(PointerRNA *ptr, const char *value)
 
 /* ****************************** */
 
+static int rna_KeyingSet_typeinfo_name_editable(PointerRNA *ptr)
+{
+       KeyingSet *ks= (KeyingSet *)ptr->data;
+       
+       /* only editable if we're using relative paths */
+       return ((ks->flag & KEYINGSET_ABSOLUTE)==0);
+}
+
 static int rna_KeyingSet_active_ksPath_editable(PointerRNA *ptr)
 {
        KeyingSet *ks= (KeyingSet *)ptr->data;
@@ -167,6 +322,91 @@ static void rna_KeyingSet_active_ksPath_index_range(PointerRNA *ptr, int *min, i
 
 #else
 
+/* helper function for Keying Set -> keying settings */
+static void rna_def_common_keying_flags(StructRNA *srna, short reg)
+{
+       PropertyRNA *prop;
+       
+       prop= RNA_def_property(srna, "insertkey_needed", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "keyingflag", INSERTKEY_NEEDED);
+       RNA_def_property_ui_text(prop, "Insert Keyframes - Only Needed", "Only insert keyframes where they're needed in the relevant F-Curves");
+       if (reg) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+       
+       prop= RNA_def_property(srna, "insertkey_visual", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "keyingflag", INSERTKEY_MATRIX);
+       RNA_def_property_ui_text(prop, "Insert Keyframes - Visual", "Insert keyframes based on 'visual transforms'");
+       if (reg) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+       
+       prop= RNA_def_property(srna, "insertkey_xyz_to_rgb", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "keyingflag", INSERTKEY_XYZ2RGB);
+       RNA_def_property_ui_text(prop, "F-Curve Colors - XYZ to RGB", "Color for newly added transformation F-Curves (Location, Rotation, Scale) and also Color is based on the transform axis");
+       if (reg) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+}
+
+/* --- */
+
+static void rna_def_keyingset_info(BlenderRNA *brna)
+{
+       StructRNA *srna;
+       PropertyRNA *prop;
+       FunctionRNA *func;
+       PropertyRNA *parm;
+       
+       srna= RNA_def_struct(brna, "KeyingSetInfo", NULL);
+       RNA_def_struct_sdna(srna, "KeyingSetInfo");
+       RNA_def_struct_ui_text(srna, "Keying Set Info", "Callback function defines for relative Keying Sets");
+       RNA_def_struct_refine_func(srna, "rna_KeyingSetInfo_refine");
+       RNA_def_struct_register_funcs(srna, "rna_KeyingSetInfo_register", "rna_KeyingSetInfo_unregister");
+       
+       /* Properties --------------------- */
+       
+       RNA_define_verify_sdna(0); // not in sdna
+               
+               /* Name */
+       prop= RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
+       RNA_def_property_string_sdna(prop, NULL, "name");
+       RNA_def_property_ui_text(prop, "Name", "");
+       RNA_def_struct_name_property(srna, prop);
+       RNA_def_property_flag(prop, PROP_REGISTER);
+       
+       prop= RNA_def_property(srna, "bl_builtin", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "builtin", 1);
+       RNA_def_property_ui_text(prop, "BuiltIn", "Keying Set type is required internally.");
+       RNA_def_property_flag(prop, PROP_REGISTER);
+       
+       rna_def_common_keying_flags(srna, 1); /* '1' arg here is to indicate that we need these to be set on registering */
+       
+       RNA_define_verify_sdna(1);
+       
+       /* Function Callbacks ------------- */
+               /* poll */
+       func= RNA_def_function(srna, "poll", NULL);
+       RNA_def_function_ui_description(func, "Test if Keying Set can be used or not");
+       RNA_def_function_flag(func, FUNC_REGISTER);
+       RNA_def_function_return(func, RNA_def_boolean(func, "ok", 1, "", ""));
+       parm= RNA_def_pointer(func, "context", "Context", "", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       
+               /* iterator */
+       func= RNA_def_function(srna, "iterator", NULL);
+       RNA_def_function_ui_description(func, "Call generate() on the structs which have properties to be keyframed");
+       RNA_def_function_flag(func, FUNC_REGISTER);
+       parm= RNA_def_pointer(func, "context", "Context", "", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm= RNA_def_pointer(func, "ks", "KeyingSet", "", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       
+               /* generate */
+       func= RNA_def_function(srna, "generate", NULL);
+       RNA_def_function_ui_description(func, "Add Paths to the Keying Set to keyframe the properties of the given data");
+       RNA_def_function_flag(func, FUNC_REGISTER);
+       parm= RNA_def_pointer(func, "context", "Context", "", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm= RNA_def_pointer(func, "ks", "KeyingSet", "", "");
+       RNA_def_property_flag(parm, PROP_REQUIRED);
+       parm= RNA_def_pointer(func, "data", NULL, "", ""); // "AnyType"...
+       RNA_def_property_flag(parm, PROP_REQUIRED|PROP_RNAPTR|PROP_NEVER_NULL);
+}
 
 static void rna_def_keyingset_path(BlenderRNA *brna)
 {
@@ -215,6 +455,9 @@ static void rna_def_keyingset_path(BlenderRNA *brna)
        prop= RNA_def_property(srna, "entire_array", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "flag", KSP_FLAG_WHOLE_ARRAY);
        RNA_def_property_ui_text(prop, "Entire Array", "When an 'array/vector' type is chosen (Location, Rotation, Color, etc.), entire array is to be used");
+       
+       /* Keyframing Settings */
+       rna_def_common_keying_flags(srna, 0);
 }
 
 static void rna_def_keyingset(BlenderRNA *brna)
@@ -230,6 +473,13 @@ static void rna_def_keyingset(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Name", "");
        RNA_def_struct_name_property(srna, prop);
        
+       /* TypeInfo associated with Relative KeyingSet (only) */
+       prop= RNA_def_property(srna, "typeinfo_name", PROP_STRING, PROP_NONE);
+       RNA_def_property_flag(prop, PROP_EDITABLE);
+       RNA_def_property_string_sdna(prop, NULL, "typeinfo");
+       RNA_def_property_editable_func(prop, "rna_KeyingSet_typeinfo_name_editable");
+       RNA_def_property_ui_text(prop, "TypeInfo Name", "");
+       
        /* Paths */
        prop= RNA_def_property(srna, "paths", PROP_COLLECTION, PROP_NONE);
        RNA_def_property_collection_sdna(prop, NULL, "paths", NULL);
@@ -249,28 +499,13 @@ static void rna_def_keyingset(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "Active Path Index", "Current Keying Set index");
        
        /* Flags */
-               // XXX: depreceated
-       prop= RNA_def_property(srna, "builtin", PROP_BOOLEAN, PROP_NONE);
-       RNA_def_property_clear_flag(prop, PROP_EDITABLE);
-       RNA_def_property_boolean_sdna(prop, NULL, "flag", KEYINGSET_BUILTIN);
-       RNA_def_property_ui_text(prop, "Built-In", "Keying Set is a built-in to Blender");
-       
        prop= RNA_def_property(srna, "absolute", PROP_BOOLEAN, PROP_NONE);
        RNA_def_property_boolean_sdna(prop, NULL, "flag", KEYINGSET_ABSOLUTE);
        RNA_def_property_ui_text(prop, "Absolute", "Keying Set defines specific paths/settings to be keyframed (i.e. is not reliant on context info)");
        
        /* Keyframing Flags */
-       prop= RNA_def_property(srna, "insertkey_needed", PROP_BOOLEAN, PROP_NONE);
-       RNA_def_property_boolean_sdna(prop, NULL, "keyingflag", INSERTKEY_NEEDED);
-       RNA_def_property_ui_text(prop, "Insert Keyframes - Only Needed", "Only insert keyframes where they're needed in the relevant F-Curves");
-       
-       prop= RNA_def_property(srna, "insertkey_visual", PROP_BOOLEAN, PROP_NONE);
-       RNA_def_property_boolean_sdna(prop, NULL, "keyingflag", INSERTKEY_MATRIX);
-       RNA_def_property_ui_text(prop, "Insert Keyframes - Visual", "Insert keyframes based on 'visual transforms'");
+       rna_def_common_keying_flags(srna, 0);
        
-       prop= RNA_def_property(srna, "insertkey_xyz_to_rgb", PROP_BOOLEAN, PROP_NONE);
-       RNA_def_property_boolean_sdna(prop, NULL, "keyingflag", INSERTKEY_XYZ2RGB);
-       RNA_def_property_ui_text(prop, "F-Curve Colors - XYZ to RGB", "Color for newly added transformation F-Curves (Location, Rotation, Scale) and also Color is based on the transform axis");
        
        /* Keying Set API */
        RNA_api_keyingset(srna);
@@ -347,6 +582,7 @@ void RNA_def_animation(BlenderRNA *brna)
        
        rna_def_keyingset(brna);
        rna_def_keyingset_path(brna);
+       rna_def_keyingset_info(brna);
 }
 
 #endif
index b07f147ac96986fbbab95424c624b4b55e22a185..46ecc8679e7e38da5f8df22d4eb6c5b376742585 100644 (file)
 
 #include "BKE_animsys.h"
 
-static void rna_KeyingSet_add_path(KeyingSet *keyingset, ReportList *reports, 
+static KS_Path *rna_KeyingSet_add_path(KeyingSet *keyingset, ReportList *reports, 
                ID *id, char rna_path[], int array_index, int entire_array,
                int grouping_method, char group_name[])
 {
+       KS_Path *ksp = NULL;
        short flag = 0;
        
        /* validate flags */
@@ -53,12 +54,31 @@ static void rna_KeyingSet_add_path(KeyingSet *keyingset, ReportList *reports,
        
        /* if data is valid, call the API function for this */
        if (keyingset) {
-               BKE_keyingset_add_path(keyingset, id, group_name, rna_path, array_index, flag, grouping_method);
+               ksp= BKE_keyingset_add_path(keyingset, id, group_name, rna_path, array_index, flag, grouping_method);
                keyingset->active_path= BLI_countlist(&keyingset->paths); 
        }
        else {
                BKE_report(reports, RPT_ERROR, "Keying Set Path could not be added.");
        }
+       
+       /* return added path */
+       return ksp;
+}
+
+static void rna_KeyingSet_remove_path(KeyingSet *keyingset, ReportList *reports, KS_Path *ksp)
+{
+       /* if data is valid, call the API function for this */
+       if (keyingset && ksp) {
+               /* remove the active path from the KeyingSet */
+               BKE_keyingset_free_path(keyingset, ksp);
+                       
+               /* the active path number will most likely have changed */
+               // TODO: we should get more fancy and actually check if it was removed, but this will do for now
+               keyingset->active_path = 0;
+       }
+       else {
+               BKE_report(reports, RPT_ERROR, "Keying Set Path could not be removed.");
+       }
 }
 
 #else
@@ -68,10 +88,13 @@ void RNA_api_keyingset(StructRNA *srna)
        FunctionRNA *func;
        PropertyRNA *parm;
        
-       /* Add Destination */
+       /* Add Path */
        func= RNA_def_function(srna, "add_path", "rna_KeyingSet_add_path");
-       RNA_def_function_ui_description(func, "Add a new destination for the Keying Set.");
+       RNA_def_function_ui_description(func, "Add a new path for the Keying Set.");
        RNA_def_function_flag(func, FUNC_USE_REPORTS);
+               /* return arg */
+       parm= RNA_def_pointer(func, "ksp", "KeyingSetPath", "New Path", "Path created and added to the Keying Set");
+               RNA_def_function_return(func, parm);
                /* ID-block for target */
        parm= RNA_def_pointer(func, "target_id", "ID", "Target ID", "ID-Datablock for the destination."); 
                RNA_def_property_flag(parm, PROP_REQUIRED);
@@ -84,6 +107,14 @@ void RNA_api_keyingset(StructRNA *srna)
                /* grouping */
        parm=RNA_def_enum(func, "grouping_method", keyingset_path_grouping_items, KSP_GROUP_KSNAME, "Grouping Method", "Method used to define which Group-name to use.");
        parm=RNA_def_string(func, "group_name", "", 64, "Group Name", "Name of Action Group to assign destination to (only if grouping mode is to use this name).");
+       
+       /* Remove Path */
+       func= RNA_def_function(srna, "remove_path", "rna_KeyingSet_remove_path");
+       RNA_def_function_ui_description(func, "Remove the given path from the Keying Set.");
+       RNA_def_function_flag(func, FUNC_USE_REPORTS);
+               /* path to remove */
+       parm= RNA_def_pointer(func, "path", "KeyingSetPath", "Path", ""); 
+               RNA_def_property_flag(parm, PROP_REQUIRED);
 }
 
 #endif
index 5302cb1eaaff4bdf7bd134c2fb1ff8313e5ed883..ae310a7f59dc9b2d02f6388d96b12816383b9300 100644 (file)
@@ -128,8 +128,6 @@ void WM_init(bContext *C, int argc, char **argv)
        BLF_init(11, U.dpi);
        BLF_lang_init();
        
-       init_builtin_keyingsets(); /* editors/animation/keyframing.c */
-       
        /* get the default database, plus a wm */
        WM_read_homefile(C, NULL);
 
@@ -281,7 +279,9 @@ void WM_exit(bContext *C)
 //     fsmenu_free();
 
        BLF_exit();
-
+       
+       ANIM_keyingset_infos_exit();
+       
        RE_FreeAllRender();
        RE_engines_exit();