2.5 - Action Editor
authorJoshua Leung <aligorith@gmail.com>
Sat, 27 Dec 2008 11:44:00 +0000 (11:44 +0000)
committerJoshua Leung <aligorith@gmail.com>
Sat, 27 Dec 2008 11:44:00 +0000 (11:44 +0000)
* Started porting back keyframe editing tools for the Action Editor/Dopesheet. Currently, only Snap (Shift-S) and Mirror (Shift-M) are functional.

* Added keyframe-editing API method for ensuring that all IPO-curves are left in a valid state after modifiying the values of their keyframes.

* Added operator-register flags for most of the operators. Only mouse-select doesn't have it for now (as there's not much useful info stored, and no exec callback).

source/blender/editors/animation/keyframes_edit.c
source/blender/editors/include/ED_keyframes_edit.h
source/blender/editors/screen/screen_ops.c
source/blender/editors/space_action/action_edit_keyframes.c [new file with mode: 0644]
source/blender/editors/space_action/action_intern.h
source/blender/editors/space_action/action_ops.c
source/blender/editors/space_action/action_select.c

index a3a0490153349080526602694ed705be38277805..e58516bf1b8466b4ad55c2744a883aa046bf15d7 100644 (file)
@@ -144,6 +144,34 @@ short animchannel_keys_bezier_loop(BeztEditData *bed, bAnimListElem *ale, BeztEd
        return 0;
 }
 
+/* ************************************************************************** */
+/* Keyframe Integrity Tools */
+
+/* Rearrange keyframes if some are out of order */
+// used to be recalc_*_ipos() where * was object or action
+void ANIM_editkeyframes_refresh(bAnimContext *ac)
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       /* filter animation data */
+       filter= ANIMFILTER_ONLYICU;
+       ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
+       
+       /* loop over ipo-curves that are likely to have been edited, and check them */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               IpoCurve *icu= ale->key_data;
+               
+               /* make sure keyframes in IPO-curve are all in order, and handles are in valid positions */
+               sort_time_ipocurve(icu);
+               testhandles_ipocurve(icu);
+       }
+       
+       /* free temp data */
+       BLI_freelistN(&anim_data);
+}
+
 /* ************************************************************************** */
 /* BezTriple Validation Callbacks */
 
@@ -286,44 +314,10 @@ static short mirror_bezier_xaxis(BeztEditData *bed, BezTriple *bezt)
 
 static short mirror_bezier_marker(BeztEditData *bed, BezTriple *bezt)
 {
-       static TimeMarker *marker;
-       static short initialised = 0;
-       const Scene *scene= bed->scene;
-       
-       /* In order for this mirror function to work without
-        * any extra arguments being added, we use the case
-        * of bezt==NULL to denote that we should find the 
-        * marker to mirror over. The static pointer is safe
-        * to use this way, as it will be set to null after 
-        * each cycle in which this is called.
-        */
-       
-       if (bezt) {
-               /* mirroring time */
-               if ((bezt->f2 & SELECT) && (marker)) {
-                       const float diff= (marker->frame - bezt->vec[1][0]);
-                       bezt->vec[1][0]= (marker->frame + diff);
-               }
-       }
-       else {
-               /* initialisation time */
-               if (initialised) {
-                       /* reset everything for safety */
-                       marker = NULL;
-                       initialised = 0;
-               }
-               else {
-                       /* try to find a marker */
-                       for (marker= scene->markers.first; marker; marker=marker->next) {
-                               if (marker->flag & SELECT) {
-                                       initialised = 1;
-                                       break;
-                               }
-                       }                       
-                       
-                       if (initialised == 0) 
-                               marker = NULL;
-               }
+       /* mirroring time stored in f1 */
+       if (bezt->f2 & SELECT) {
+               const float diff= (bed->f1 - bezt->vec[1][0]);
+               bezt->vec[1][0]= (bed->f1 + diff);
        }
        
        return 0;
@@ -334,20 +328,22 @@ static short mirror_bezier_marker(BeztEditData *bed, BezTriple *bezt)
 BeztEditFunc ANIM_editkeyframes_mirror(short type)
 {
        switch (type) {
-               case 1: /* mirror over current frame */
+               case MIRROR_KEYS_CURFRAME: /* mirror over current frame */
                        return mirror_bezier_cframe;
-               case 2: /* mirror over frame 0 */
+               case MIRROR_KEYS_YAXIS: /* mirror over frame 0 */
                        return mirror_bezier_yaxis;
-               case 3: /* mirror over value 0 */
+               case MIRROR_KEYS_XAXIS: /* mirror over value 0 */
                        return mirror_bezier_xaxis;
-               case 4: /* mirror over marker */
-                       return mirror_bezier_marker; // XXX in past, this func was called before/after with NULL, probably will need globals instead
+               case MIRROR_KEYS_MARKER: /* mirror over marker */
+                       return mirror_bezier_marker; 
                default: /* just in case */
                        return mirror_bezier_yaxis;
                        break;
        }
 }
 
+/* --------- */
+
 /* This function is called to calculate the average location of the
  * selected keyframes, and place the current frame at that location.
  *
@@ -654,6 +650,7 @@ short is_ipo_key_selected(Ipo *ipo)
        return 0;
 }
 
+// XXX although this is still needed, it should be removed!
 void set_ipo_key_selection(Ipo *ipo, short sel)
 {
        IpoCurve *icu;
@@ -678,6 +675,7 @@ void set_ipo_key_selection(Ipo *ipo, short sel)
        }
 }
 
+// XXX port this over to the new system!
 // err... this is this still used?
 int fullselect_ipo_keys(Ipo *ipo)
 {
@@ -701,134 +699,3 @@ int fullselect_ipo_keys(Ipo *ipo)
        return tvtot;
 }
 
-
-void borderselect_icu_key(IpoCurve *icu, float xmin, float xmax, BeztEditFunc select_cb)
-{
-       /* Selects all bezier triples in the Ipocurve 
-        * between times xmin and xmax, using the selection
-        * function.
-        */
-       BezTriple *bezt;
-       int i;
-       
-       /* loop through all of the bezier triples in
-        * the Ipocurve -- if the triple occurs between
-        * times xmin and xmax then select it using the selection
-        * function
-        */
-       for (i=0, bezt=icu->bezt; i<icu->totvert; i++, bezt++) {
-               if ((bezt->vec[1][0] > xmin) && (bezt->vec[1][0] < xmax)) {
-                       /* scene is NULL (irrelevant here) */
-                       select_cb(NULL, bezt); 
-               }
-       }
-}
-
-void borderselect_ipo_key(Ipo *ipo, float xmin, float xmax, short selectmode)
-{
-       /* Selects all bezier triples in each Ipocurve of the
-        * Ipo between times xmin and xmax, using the selection mode.
-        */
-       
-       IpoCurve *icu;
-       BeztEditFunc select_cb;
-       
-       /* If the ipo is no good then return */
-       if (ipo == NULL)
-               return;
-       
-       /* Set the selection function based on the
-        * selection mode.
-        */
-       select_cb= ANIM_editkeyframes_select(selectmode);
-       if (select_cb == NULL)
-               return;
-       
-       /* loop through all of the bezier triples in all
-               * of the Ipocurves -- if the triple occurs between
-               * times xmin and xmax then select it using the selection
-               * function
-               */
-       for (icu=ipo->curve.first; icu; icu=icu->next) {
-               borderselect_icu_key(icu, xmin, xmax, select_cb);
-       }
-}
-
-void select_icu_key(BeztEditData *bed, IpoCurve *icu, float selx, short selectmode)
-{
-    /* Selects all bezier triples in the Ipocurve
-        * at time selx, using the selection mode.
-        * This is kind of sloppy the obvious similarities
-        * with the above function, forgive me ...
-        */
-    BeztEditFunc select_cb;
-       BezTriple *bezt;
-       int i;
-       
-    /* If the icu is no good then return */
-    if (icu == NULL)
-        return;
-       
-    /* Set the selection function based on the selection mode. */
-    switch (selectmode) {
-               case SELECT_ADD:
-                       select_cb = select_bezier_add;
-                       break;
-               case SELECT_SUBTRACT:
-                       select_cb = select_bezier_subtract;
-                       break;
-               case SELECT_INVERT:
-                       select_cb = select_bezier_invert;
-                       break;
-               default:
-                       return;
-    }
-       
-    /* loop through all of the bezier triples in
-        * the Ipocurve -- if the triple occurs at
-        * time selx then select it using the selection
-        * function
-        */
-    for (i=0, bezt=icu->bezt; i<icu->totvert; i++, bezt++) {
-        if (bezt->vec[1][0] == selx) {
-            select_cb(bed, bezt);
-        }
-    }
-}
-
-void select_ipo_key(BeztEditData *bed, Ipo *ipo, float selx, short selectmode)
-{
-       /* Selects all bezier triples in each Ipocurve of the
-        * Ipo at time selx, using the selection mode.
-        */
-       IpoCurve *icu;
-       BezTriple *bezt;
-       BeztEditFunc select_cb;
-       int i;
-       
-       /* If the ipo is no good then return */
-       if (ipo == NULL)
-               return;
-       
-       /* Set the selection function based on the
-        * selection mode.
-        */
-       select_cb= ANIM_editkeyframes_select(selectmode);
-       if (select_cb == NULL)
-               return;
-       
-       /* loop through all of the bezier triples in all
-        * of the Ipocurves -- if the triple occurs at
-        * time selx then select it using the selection
-        * function
-        */
-       for (icu=ipo->curve.first; icu; icu=icu->next) {
-               for (i=0, bezt=icu->bezt; i<icu->totvert; i++, bezt++) {
-                       if (bezt->vec[1][0] == selx) {
-                               select_cb(bed, bezt);
-                       }
-               }
-       }
-}
-
-
index 56a4cb6089c78b06b5cc179ae53c36ac2470d15a..36ec834635e7f4de3fefbe75e6b8e60d1f9b29eb 100644 (file)
@@ -29,6 +29,7 @@
 #ifndef ED_KEYFRAMES_EDIT_H
 #define ED_KEYFRAMES_EDIT_H
 
+struct bAnimContext;
 struct Ipo;
 struct IpoCurve;
 struct BezTriple;
@@ -67,16 +68,19 @@ typedef enum eEditKeyframes_Select {
 
 /* snapping tools */
 typedef enum eEditKeyframes_Snap {
-       SNAP_KEYS_NEARFRAME     = 1,
-       SNAP_KEYS_CURFRAME,
-       SNAP_KEYS_NEARMARKER,
+       SNAP_KEYS_CURFRAME = 1,
+       SNAP_KEYS_NEARFRAME,
        SNAP_KEYS_NEARSEC,
+       SNAP_KEYS_NEARMARKER,
 } eEditKeyframes_Snap;
 
 /* mirroring tools */
-//typedef enum eEditKeyframes_Mirror {
-       
-//} eEditKeyframes_Mirror;
+typedef enum eEditKeyframes_Mirror {
+       MIRROR_KEYS_CURFRAME = 1,
+       MIRROR_KEYS_YAXIS,
+       MIRROR_KEYS_XAXIS,
+       MIRROR_KEYS_MARKER,
+} eEditKeyframes_Mirror;
 
 /* ************************************************ */
 /* Editing API */
@@ -92,19 +96,23 @@ typedef struct BeztEditData {
        int i1, i2;                                     /* storage of times/values as 'whole' numbers */
 } BeztEditData;
 
-/* ------- Function Pointer Typedefs --------------- */
+/* ------- Function Pointer Typedefs ---------------- */
 
        /* callback function that refreshes the IPO curve after use */
 typedef void (*IcuEditFunc)(struct IpoCurve *icu);
        /* callback function that operates on the given BezTriple */
 typedef short (*BeztEditFunc)(BeztEditData *bed, struct BezTriple *bezt);
 
-/* ------------- Looping API ------------------- */
+/* ---------------- Looping API --------------------- */
 
+/* functions for looping over keyframes */
 short icu_keys_bezier_loop(BeztEditData *bed, struct IpoCurve *icu, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, IcuEditFunc icu_cb);
 short ipo_keys_bezier_loop(BeztEditData *bed, struct Ipo *ipo, BeztEditFunc bezt_ok, BeztEditFunc bezt_cb, IcuEditFunc icu_cb);
 
-/* ------------ BezTriple Callback Getters --------------- */
+/* functions for making sure all keyframes are in good order */
+void ANIM_editkeyframes_refresh(struct bAnimContext *ac);
+
+/* ----------- BezTriple Callback Getters ---------- */
 
 /* accessories */
 BeztEditFunc ANIM_editkeyframes_ok(short mode);
@@ -120,15 +128,9 @@ BeztEditFunc ANIM_editkeyframes_ipo(short mode);
 
 // XXX all of these funcs will be depreceated!
 
-void select_ipo_key(BeztEditData *bed, struct Ipo *ipo, float selx, short selectmode);
-void select_icu_key(BeztEditData *bed, struct IpoCurve *icu, float selx, short selectmode);
-
 short is_ipo_key_selected(struct Ipo *ipo);
 void set_ipo_key_selection(struct Ipo *ipo, short sel);
 
-void borderselect_ipo_key(struct Ipo *ipo, float xmin, float xmax, short selectmode);
-void borderselect_icu_key(struct IpoCurve *icu, float xmin, float xmax, BeztEditFunc select_cb);
-
 
 /* ************************************************ */
 
index 6dfb99397f733cdcec068d12f37fcebfffc8e2f7..5f38081f7fc9ecb9681f0bb2c13959298b89cfc3 100644 (file)
@@ -1525,9 +1525,9 @@ void ED_keymap_screen(wmWindowManager *wm)
        WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL, 0);
 
         /* tests */
-       RNA_enum_set(WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, 0, 0)->ptr, "dir", 'h');
-       RNA_enum_set(WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "dir", 'v');
-                                                 
+       RNA_enum_set(WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT, 0)->ptr, "dir", 'h');
+       RNA_enum_set(WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0)->ptr, "dir", 'v');
+       
        /*frame offsets*/
        WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", TIMER0, KM_ANY, KM_ANY, 0);
        RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
diff --git a/source/blender/editors/space_action/action_edit_keyframes.c b/source/blender/editors/space_action/action_edit_keyframes.c
new file mode 100644 (file)
index 0000000..8423aeb
--- /dev/null
@@ -0,0 +1,352 @@
+/**
+ * $Id: editaction.c 17746 2008-12-08 11:19:44Z aligorith $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <float.h>
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_listBase.h"
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "BKE_action.h"
+#include "BKE_depsgraph.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_material.h"
+#include "BKE_object.h"
+#include "BKE_context.h"
+#include "BKE_utildefines.h"
+
+#include "UI_view2d.h"
+
+#include "ED_anim_api.h"
+#include "ED_keyframing.h"
+#include "ED_keyframes_draw.h"
+#include "ED_keyframes_edit.h"
+#include "ED_screen.h"
+#include "ED_space_api.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "action_intern.h"
+
+/* ************************************************************************** */
+/* GENERAL STUFF */
+
+/* ************************************************************************** */
+/* SETTINGS STUFF */
+
+/* ************************************************************************** */
+/* TRANSFORM STUFF */
+
+/* ***************** Snap Current Frame Operator *********************** */
+
+/* snap current-frame indicator to 'average time' of selected keyframe */
+static int actkeys_cfrasnap_exec(bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       
+       //ListBase anim_data= {NULL, NULL};
+       //bAnimListElem *ale;
+       //int filter;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+       
+       // FIXME... to be coded
+       
+       /* set notifier tha things have changed */
+       ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
+       
+       return OPERATOR_FINISHED;
+}
+
+void ACT_OT_keyframes_cfrasnap (wmOperatorType *ot)
+{
+       PropertyRNA *prop;
+       
+       /* identifiers */
+       ot->name= "Current Frame Snap to Keys";
+       ot->idname= "ACT_OT_keyframes_cfrasnap";
+       
+       /* api callbacks */
+       ot->exec= actkeys_cfrasnap_exec;
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+}
+
+/* ******************** Snap Keyframes Operator *********************** */
+
+/* defines for snap keyframes tool */
+EnumPropertyItem prop_actkeys_snap_types[] = {
+       {ACTKEYS_SNAP_CFRA, "CFRA", "Current frame", ""},
+       {ACTKEYS_SNAP_NEAREST_FRAME, "NEAREST_FRAME", "Nearest Frame", ""}, // XXX as single entry?
+       {ACTKEYS_SNAP_NEAREST_SECOND, "NEAREST_SECOND", "Nearest Second", ""}, // XXX as single entry?
+       {ACTKEYS_SNAP_NEAREST_MARKER, "NEAREST_MARKER", "Nearest Marker", ""},
+       {0, NULL, NULL, NULL}
+};
+
+/* this function is responsible for snapping keyframes to frame-times */
+static void snap_action_keys(bAnimContext *ac, short mode) 
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       BeztEditData bed;
+       BeztEditFunc edit_cb;
+       
+       /* filter data */
+       if (ac->datatype == ANIMCONT_GPENCIL)
+               filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
+       else
+               filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
+       ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
+       
+       /* get beztriple editing callbacks */
+       edit_cb= ANIM_editkeyframes_snap(mode);
+       
+       memset(&bed, 0, sizeof(BeztEditData)); 
+       bed.scene= ac->scene;
+       
+       /* snap keyframes */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               Object *nob= ANIM_nla_mapping_get(ac, ale);
+               
+               if (nob) {
+                       ANIM_nla_mapping_apply(nob, ale->key_data, 0, 1); 
+                       ipo_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_ipocurve);
+                       ANIM_nla_mapping_apply(nob, ale->key_data, 1, 1);
+               }
+               //else if (ale->type == ACTTYPE_GPLAYER)
+               //      snap_gplayer_frames(ale->data, mode);
+               else 
+                       ipo_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_ipocurve);
+       }
+       BLI_freelistN(&anim_data);
+}
+
+/* ------------------- */
+
+static int actkeys_snap_exec(bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       short mode;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+               
+       /* get snapping mode */
+       mode= RNA_enum_get(op->ptr, "type");
+       
+       /* snap keyframes */
+       snap_action_keys(&ac, mode);
+       
+       /* validate keyframes after editing */
+       ANIM_editkeyframes_refresh(&ac);
+       
+       /* set notifier tha things have changed */
+       ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
+       
+       return OPERATOR_FINISHED;
+}
+void ACT_OT_keyframes_snap (wmOperatorType *ot)
+{
+       PropertyRNA *prop;
+       
+       /* identifiers */
+       ot->name= "Snap Keys";
+       ot->idname= "ACT_OT_keyframes_snap";
+       
+       /* api callbacks */
+       ot->invoke= WM_menu_invoke;
+       ot->exec= actkeys_snap_exec;
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       
+       /* id-props */
+       prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_items(prop, prop_actkeys_snap_types);
+}
+
+/* ******************** Mirror Keyframes Operator *********************** */
+
+/* defines for snap keyframes tool */
+EnumPropertyItem prop_actkeys_mirror_types[] = {
+       {ACTKEYS_MIRROR_CFRA, "CFRA", "Current frame", ""},
+       {ACTKEYS_MIRROR_YAXIS, "YAXIS", "Vertical Axis", ""},
+       {ACTKEYS_MIRROR_XAXIS, "XAXIS", "Horizontal Axis", ""},
+       {ACTKEYS_MIRROR_MARKER, "MARKER", "First Selected Marker", ""},
+       {0, NULL, NULL, NULL}
+};
+
+/* this function is responsible for snapping keyframes to frame-times */
+static void mirror_action_keys(bAnimContext *ac, short mode) 
+{
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       BeztEditData bed;
+       BeztEditFunc edit_cb;
+       
+       /* get beztriple editing callbacks */
+       edit_cb= ANIM_editkeyframes_mirror(mode);
+       
+       memset(&bed, 0, sizeof(BeztEditData)); 
+       bed.scene= ac->scene;
+       
+       /* for 'first selected marker' mode, need to find first selected marker first! */
+       // XXX should this be made into a helper func in the API?
+       if (mode == ACTKEYS_MIRROR_MARKER) {
+               Scene *scene= ac->scene;
+               TimeMarker *marker= NULL;
+               
+               /* find first selected marker */
+               for (marker= scene->markers.first; marker; marker=marker->next) {
+                       if (marker->flag & SELECT) {
+                               break;
+                       }
+               }
+               
+               /* store marker's time (if available) */
+               if (marker)
+                       bed.f1= marker->frame;
+               else
+                       return;
+       }
+       
+       /* filter data */
+       if (ac->datatype == ANIMCONT_GPENCIL)
+               filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT);
+       else
+               filter= (ANIMFILTER_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_IPOKEYS);
+       ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
+       
+       /* mirror keyframes */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               Object *nob= ANIM_nla_mapping_get(ac, ale);
+               
+               if (nob) {
+                       ANIM_nla_mapping_apply(nob, ale->key_data, 0, 1); 
+                       ipo_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_ipocurve);
+                       ANIM_nla_mapping_apply(nob, ale->key_data, 1, 1);
+               }
+               //else if (ale->type == ACTTYPE_GPLAYER)
+               //      snap_gplayer_frames(ale->data, mode);
+               else 
+                       ipo_keys_bezier_loop(&bed, ale->key_data, NULL, edit_cb, calchandles_ipocurve);
+       }
+       BLI_freelistN(&anim_data);
+}
+
+/* ------------------- */
+
+static int actkeys_mirror_exec(bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       short mode;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+               
+       /* get snapping mode */
+       mode= RNA_enum_get(op->ptr, "type");
+       
+       /* mirror keyframes */
+       mirror_action_keys(&ac, mode);
+       
+       /* validate keyframes after editing */
+       ANIM_editkeyframes_refresh(&ac);
+       
+       /* set notifier tha things have changed */
+       ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
+       
+       return OPERATOR_FINISHED;
+}
+void ACT_OT_keyframes_mirror (wmOperatorType *ot)
+{
+       PropertyRNA *prop;
+       
+       /* identifiers */
+       ot->name= "Mirror Keys";
+       ot->idname= "ACT_OT_keyframes_mirror";
+       
+       /* api callbacks */
+       ot->invoke= WM_menu_invoke;
+       ot->exec= actkeys_mirror_exec;
+       ot->poll= ED_operator_areaactive;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       
+       /* id-props */
+       prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
+       RNA_def_property_enum_items(prop, prop_actkeys_mirror_types);
+}
+
+/* ************************************************************************** */
index 27d8ada37acba4b830eae534a1522b04abde2e66..7719bf4ba34ef254697665484b617dd7fdec6da4 100644 (file)
@@ -48,6 +48,7 @@ void action_header_buttons(const struct bContext *C, struct ARegion *ar);
 
 /* ***************************************** */
 /* action_select.c */
+
 void ACT_OT_keyframes_deselectall(struct wmOperatorType *ot);
 void ACT_OT_keyframes_borderselect(struct wmOperatorType *ot);
 void ACT_OT_keyframes_columnselect(struct wmOperatorType *ot);
@@ -69,6 +70,32 @@ enum {
        ACTKEYS_COLUMNSEL_MARKERS_BETWEEN,
 } eActKeys_ColumnSelect_Mode;
 
+/* ***************************************** */
+/* action_edit_keyframes.c */
+
+void ACT_OT_keyframes_snap(struct wmOperatorType *ot);
+void ACT_OT_keyframes_mirror(struct wmOperatorType *ot);
+
+/* defines for snap keyframes 
+ * NOTE: keep in sync with eEditKeyframes_Snap (in ED_keyframes_edit.h)
+ */
+enum {
+       ACTKEYS_SNAP_CFRA = 1,
+       ACTKEYS_SNAP_NEAREST_FRAME,
+       ACTKEYS_SNAP_NEAREST_SECOND,
+       ACTKEYS_SNAP_NEAREST_MARKER,    
+} eActKeys_Snap_Mode;
+
+/* defines for mirror keyframes 
+ * NOTE: keep in sync with eEditKeyframes_Mirror (in ED_keyframes_edit.h)
+ */
+enum {
+       ACTKEYS_MIRROR_CFRA = 1,
+       ACTKEYS_MIRROR_YAXIS,
+       ACTKEYS_MIRROR_XAXIS,
+       ACTKEYS_MIRROR_MARKER,  
+} eActKeys_Mirror_Mode;
+       
 /* ***************************************** */
 /* action_ops.c */
 void action_operatortypes(void);
index 19850917a9c3a6775095cfc1a186a9f3b6d18134..51b8800c1ea2a2de9d6a49e4cb79355291feb4a1 100644 (file)
@@ -62,10 +62,15 @@ void action_operatortypes(void)
        /* channels */
        
        /* keyframes */
+               /* selection */
        WM_operatortype_append(ACT_OT_keyframes_clickselect);
        WM_operatortype_append(ACT_OT_keyframes_deselectall);
        WM_operatortype_append(ACT_OT_keyframes_borderselect);
        WM_operatortype_append(ACT_OT_keyframes_columnselect);
+       
+               /* editing */
+       WM_operatortype_append(ACT_OT_keyframes_snap);
+       WM_operatortype_append(ACT_OT_keyframes_mirror);
 }
 
 /* ************************** registration - keymaps **********************************/
@@ -79,7 +84,6 @@ static void action_keymap_keyframes (ListBase *keymap)
        RNA_boolean_set(WM_keymap_add_item(keymap, "ACT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend_select", 1);
        RNA_enum_set(WM_keymap_add_item(keymap, "ACT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "left_right", ACTKEYS_LRSEL_TEST);
        
-       
                /* deselect all */
        WM_keymap_add_item(keymap, "ACT_OT_keyframes_deselectall", AKEY, KM_PRESS, 0, 0);
        RNA_boolean_set(WM_keymap_add_item(keymap, "ACT_OT_keyframes_deselectall", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
@@ -93,6 +97,11 @@ static void action_keymap_keyframes (ListBase *keymap)
        RNA_enum_set(WM_keymap_add_item(keymap, "ACT_OT_keyframes_columnselect", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_CFRA);
        RNA_enum_set(WM_keymap_add_item(keymap, "ACT_OT_keyframes_columnselect", KKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_MARKERS_COLUMN);
        RNA_enum_set(WM_keymap_add_item(keymap, "ACT_OT_keyframes_columnselect", KKEY, KM_PRESS, KM_ALT, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_MARKERS_BETWEEN);
+       
+       /* action_edit_keyframes.c */
+               /* menu+1-step transform */
+       WM_keymap_add_item(keymap, "ACT_OT_keyframes_snap", SKEY, KM_PRESS, KM_SHIFT, 0);
+       WM_keymap_add_item(keymap, "ACT_OT_keyframes_mirror", MKEY, KM_PRESS, KM_SHIFT, 0);
 }
 
 /* --------------- */
index de41b7e4604b2136a3a6cbf84cce8923c515e497..46bf25490871222f5980e063ddef131df8d734d5 100644 (file)
@@ -411,6 +411,9 @@ void ACT_OT_keyframes_deselectall (wmOperatorType *ot)
        ot->exec= actkeys_deselectall_exec;
        ot->poll= ED_operator_areaactive;
        
+       /* flags */
+       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       
        /* props */
        RNA_def_property(ot->srna, "invert", PROP_BOOLEAN, PROP_NONE);
 }
@@ -577,6 +580,10 @@ void ACT_OT_keyframes_borderselect(wmOperatorType *ot)
        
        ot->poll= ED_operator_areaactive;
        
+       /* flags */
+       // XXX er...
+       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       
        /* rna */
        RNA_def_property(ot->srna, "event_type", PROP_INT, PROP_NONE);
        RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
@@ -809,6 +816,9 @@ void ACT_OT_keyframes_columnselect (wmOperatorType *ot)
        ot->exec= actkeys_columnselect_exec;
        ot->poll= ED_operator_areaactive;
        
+       /* flags */
+       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       
        /* props */
        prop= RNA_def_property(ot->srna, "mode", PROP_ENUM, PROP_NONE);
        RNA_def_property_enum_items(prop, prop_column_select_types);
@@ -1007,21 +1017,29 @@ static void selectkeys_leftright (bAnimContext *ac, short leftright, short selec
        ListBase anim_data = {NULL, NULL};
        bAnimListElem *ale;
        int filter;
+       
+       BeztEditFunc ok_cb, select_cb;
+       BeztEditData bed;
        Scene *scene= ac->scene;
-       float min, max;
        
+       /* if select mode is replace, deselect all keyframes first */
        if (select_mode==SELECT_REPLACE) {
                select_mode=SELECT_ADD;
                deselect_action_keys(ac, 0, 0);
        }
        
+       /* set callbacks and editing data */
+       ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
+       select_cb= ANIM_editkeyframes_select(select_mode);
+       
+       memset(&bed, 0, sizeof(BeztEditFunc));
        if (leftright == ACTKEYS_LRSEL_LEFT) {
-               min = -MAXFRAMEF;
-               max = (float)(CFRA + 0.1f);
+               bed.f1 = -MAXFRAMEF;
+               bed.f2 = (float)(CFRA + 0.1f);
        } 
        else {
-               min = (float)(CFRA - 0.1f);
-               max = MAXFRAMEF;
+               bed.f1 = (float)(CFRA - 0.1f);
+               bed.f2 = MAXFRAMEF;
        }
        
        /* filter data */
@@ -1037,13 +1055,13 @@ static void selectkeys_leftright (bAnimContext *ac, short leftright, short selec
                
                if (nob) {
                        ANIM_nla_mapping_apply(nob, ale->key_data, 0, 1);
-                       borderselect_ipo_key(ale->key_data, min, max, SELECT_ADD);
+                       ipo_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
                        ANIM_nla_mapping_apply(nob, ale->key_data, 1, 1);
                }
                //else if (ale->type == ANIMTYPE_GPLAYER)
                //      borderselect_gplayer_frames(ale->data, min, max, SELECT_ADD);
                else
-                       borderselect_ipo_key(ale->key_data, min, max, SELECT_ADD);
+                       ipo_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
        }
        
        /* Cleanup */