Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Leung <aligorith@gmail.com>2008-12-23 14:02:39 +0300
committerJoshua Leung <aligorith@gmail.com>2008-12-23 14:02:39 +0300
commit87c05f7836e5b646e0053bd23f138bc36ab18773 (patch)
tree97bd56f7e3f9a28cf544dc904ba0790697764a5b /source/blender/editors/animation/keyframes_edit.c
parent58da63cd3efb8c4a1789f0a49afa144c40c551b0 (diff)
2.5 Action Editor - Big WIP Commit
* Brought back backend for editing keyframes IPO/IPO-Curves. Did some refactoring work here that will still have to be verified when operators using them are added. * Animation channel filtering code now returns the number of channels filtered (for Action Editor to set totrect of channels - TODO still!) * View2D - made function to check if mouse is in View2D scrollers an API function * Renamed keyframe related files. The old names were too clumsy. * Started porting click-select operators for Action Editor. These don't work currently, as the events are being stolen by the markers. This needs to be fixed ASAP.
Diffstat (limited to 'source/blender/editors/animation/keyframes_edit.c')
-rw-r--r--source/blender/editors/animation/keyframes_edit.c785
1 files changed, 785 insertions, 0 deletions
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
new file mode 100644
index 00000000000..152d07b83f6
--- /dev/null
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -0,0 +1,785 @@
+/**
+ * $Id:
+ *
+ * ***** 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.
+ *
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_action.h"
+#include "BKE_ipo.h"
+#include "BKE_key.h"
+#include "BKE_utildefines.h"
+
+#include "ED_keyframes_edit.h"
+#include "ED_markers.h"
+
+/* This file defines an API and set of callback-operators for editing keyframe data.
+ *
+ * Two API functions are defined for actually performing the operations on the data:
+ * ipo_keys_bezier_loop() and icu_keys_bezier_loop()
+ * which take the data they operate on, a few callbacks defining what operations to perform.
+ *
+ * As operators which work on keyframes usually apply the same operation on all BezTriples in
+ * every channel, the code has been optimised providing a set of functions which will get the
+ * appropriate bezier-modify function to set. These functions (ANIM_editkeyframes_*) will need
+ * to be called before getting any channels.
+ *
+ * - Joshua Leung, Dec 2008
+ */
+
+/* ************************************************************************** */
+/* IPO Editing Loops - Exposed API */
+
+// FIXME: it would be useful to be able to supply custom properties to the bezt function...
+// workaround for those callbacks that need this now, is to set globals...
+
+/* This function is used to loop over BezTriples in the given IpoCurve, applying a given
+ * operation on them, and optionally applies an IPO-curve validate function afterwards.
+ */
+short icu_keys_bezier_loop(Scene *scene, IpoCurve *icu, BeztEditFunc bezt_cb, IcuEditFunc icu_cb)
+{
+ BezTriple *bezt;
+ int b;
+
+ /* if function to apply to bezier curves is set, then loop through executing it on beztriples */
+ if (bezt_cb) {
+ for (b=0, bezt=icu->bezt; b < icu->totvert; b++, bezt++) {
+ /* Exit with return-code '1' if function returns positive
+ * This is useful if finding if some BezTriple satisfies a condition.
+ */
+ if (bezt_cb(scene, bezt)) return 1;
+ }
+ }
+
+ /* if ipocurve_function has been specified then execute it */
+ if (icu_cb)
+ icu_cb(icu);
+
+ /* done */
+ return 0;
+}
+
+/* This function is used to loop over the IPO curves (and subsequently the keyframes in them) */
+short ipo_keys_bezier_loop(Scene *scene, Ipo *ipo, BeztEditFunc bezt_cb, IcuEditFunc icu_cb)
+{
+ IpoCurve *icu;
+
+ /* Sanity check */
+ if (ipo == NULL)
+ return 0;
+
+ /* Loop through each curve in the Ipo */
+ for (icu= ipo->curve.first; icu; icu=icu->next) {
+ if (icu_keys_bezier_loop(scene, icu, bezt_cb, icu_cb))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* ******************************************* */
+/* Transform */
+
+static short snap_bezier_nearest(Scene *scene, BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]+0.5));
+ return 0;
+}
+
+static short snap_bezier_nearestsec(Scene *scene, BezTriple *bezt)
+{
+ float secf = FPS;
+ if (bezt->f2 & SELECT)
+ bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]/secf + 0.5f) * secf);
+ return 0;
+}
+
+static short snap_bezier_cframe(Scene *scene, BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->vec[1][0]= (float)CFRA;
+ return 0;
+}
+
+static short snap_bezier_nearmarker(Scene *scene, BezTriple *bezt)
+{
+ //if (bezt->f2 & SELECT)
+ // bezt->vec[1][0]= (float)find_nearest_marker_time(bezt->vec[1][0]); // XXX missing function!
+ return 0;
+}
+
+// calchandles_ipocurve
+BeztEditFunc ANIM_editkeys_snap(short type)
+{
+ switch (type) {
+ case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
+ return snap_bezier_nearest;
+ case SNAP_KEYS_CURFRAME: /* snap to current frame */
+ return snap_bezier_cframe;
+ case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */
+ return snap_bezier_nearmarker;
+ case SNAP_KEYS_NEARSEC: /* snap to nearest second */
+ return snap_bezier_nearestsec;
+ default: /* just in case */
+ return snap_bezier_nearest;
+ }
+}
+
+/* --------- */
+
+static short mirror_bezier_cframe(Scene *scene, BezTriple *bezt)
+{
+ float diff;
+
+ if (bezt->f2 & SELECT) {
+ diff= ((float)CFRA - bezt->vec[1][0]);
+ bezt->vec[1][0]= ((float)CFRA + diff);
+ }
+
+ return 0;
+}
+
+static short mirror_bezier_yaxis(Scene *scene, BezTriple *bezt)
+{
+ float diff;
+
+ if (bezt->f2 & SELECT) {
+ diff= (0.0f - bezt->vec[1][0]);
+ bezt->vec[1][0]= (0.0f + diff);
+ }
+
+ return 0;
+}
+
+static short mirror_bezier_xaxis(Scene *scene, BezTriple *bezt)
+{
+ float diff;
+
+ if (bezt->f2 & SELECT) {
+ diff= (0.0f - bezt->vec[1][1]);
+ bezt->vec[1][1]= (0.0f + diff);
+ }
+
+ return 0;
+}
+
+static short mirror_bezier_marker(Scene *scene, BezTriple *bezt)
+{
+ static TimeMarker *marker;
+ static short initialised = 0;
+
+ /* 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;
+ }
+ }
+
+ return 0;
+}
+
+/* Note: for markers case, need to set global vars (eww...) */
+// calchandles_ipocurve
+BeztEditFunc ANIM_editkeyframes_mirror(short type)
+{
+ switch (type) {
+ case 1: /* mirror over current frame */
+ return mirror_bezier_cframe;
+ case 2: /* mirror over frame 0 */
+ return mirror_bezier_yaxis;
+ case 3: /* 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
+ 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.
+ *
+ * It must be called like so:
+ * snap_cfra_ipo_keys(scene, NULL, -1); // initialise the static vars first
+ * for (ipo...) snap_cfra_ipo_keys(scene, ipo, 0); // sum up keyframe times
+ * snap_cfra_ipo_keys(scene, NULL, 1); // set current frame after taking average
+ */
+void snap_cfra_ipo_keys(Scene *scene, Ipo *ipo, short mode)
+{
+ static int cfra;
+ static int tot;
+
+ IpoCurve *icu;
+ BezTriple *bezt;
+ int a;
+
+
+ if (mode == -1) {
+ /* initialise a new snap-operation */
+ cfra= 0;
+ tot= 0;
+ }
+ else if (mode == 1) {
+ /* set current frame - using average frame */
+ if (tot != 0)
+ CFRA = cfra / tot;
+ }
+ else {
+ /* loop through keys in ipo, summing the frame
+ * numbers of those that are selected
+ */
+ if (ipo == NULL)
+ return;
+
+ for (icu= ipo->curve.first; icu; icu= icu->next) {
+ for (a=0, bezt=icu->bezt; a < icu->totvert; a++, bezt++) {
+ if (BEZSELECTED(bezt)) {
+ cfra += bezt->vec[1][0];
+ tot++;
+ }
+ }
+ }
+ }
+}
+
+/* ******************************************* */
+/* Settings */
+
+/* Sets the selected bezier handles to type 'auto' */
+static short set_bezier_auto(Scene *scene, BezTriple *bezt)
+{
+ /* is a handle selected? If so set it to type auto */
+ if((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
+ if (bezt->f1 & SELECT) bezt->h1= 1; /* the secret code for auto */
+ if (bezt->f3 & SELECT) bezt->h2= 1;
+
+ /* if the handles are not of the same type, set them
+ * to type free
+ */
+ if (bezt->h1 != bezt->h2) {
+ if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE;
+ if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE;
+ }
+ }
+ return 0;
+}
+
+/* Sets the selected bezier handles to type 'vector' */
+static short set_bezier_vector(Scene *scene, BezTriple *bezt)
+{
+ /* is a handle selected? If so set it to type vector */
+ if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) {
+ if (bezt->f1 & SELECT) bezt->h1= HD_VECT;
+ if (bezt->f3 & SELECT) bezt->h2= HD_VECT;
+
+ /* if the handles are not of the same type, set them
+ * to type free
+ */
+ if (bezt->h1 != bezt->h2) {
+ if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE;
+ if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE;
+ }
+ }
+ return 0;
+}
+
+#if 0 // xxx currently not used (only used by old code as a check)
+static short bezier_isfree(Scene *scene, BezTriple *bezt)
+{
+ /* queries whether the handle should be set
+ * to type 'free' or 'align'
+ */
+ if ((bezt->f1 & SELECT) && (bezt->h1)) return 1;
+ if ((bezt->f3 & SELECT) && (bezt->h2)) return 1;
+ return 0;
+}
+
+static short set_bezier_align(Scene *scene, BezTriple *bezt)
+{
+ /* Sets selected bezier handles to type 'align' */
+ if (bezt->f1 & SELECT) bezt->h1= HD_ALIGN;
+ if (bezt->f3 & SELECT) bezt->h2= HD_ALIGN;
+ return 0;
+}
+#endif // xxx currently not used (only used by old code as a check, but can't replicate that now)
+
+static short set_bezier_free(Scene *scene, BezTriple *bezt)
+{
+ /* Sets selected bezier handles to type 'free' */
+ if (bezt->f1 & SELECT) bezt->h1= HD_FREE;
+ if (bezt->f3 & SELECT) bezt->h2= HD_FREE;
+ return 0;
+}
+
+/* Set all Bezier Handles to a single type */
+// calchandles_ipocurve
+BeztEditFunc ANIM_editkeyframes_sethandles(short code)
+{
+ switch (code) {
+ case 1: /* auto */
+ return set_bezier_auto;
+ case 2: /* vector */
+ return set_bezier_vector;
+
+ default: /* free or align? */
+ return set_bezier_free; // err.. to set align, we need 'align' to be set
+ }
+}
+
+#if 0
+void sethandles_ipo_keys(Ipo *ipo, int code)
+{
+ /* this function lets you set bezier handles all to
+ * one type for some Ipo's (e.g. with hotkeys through
+ * the action window).
+ */
+
+ /* code==1: set autohandle */
+ /* code==2: set vectorhandle */
+ /* als code==3 (HD_ALIGN) toggelt het, vectorhandles worden HD_FREE */
+
+ switch (code) {
+ case 1: /* auto */
+ ipo_keys_bezier_loop(ipo, set_bezier_auto, calchandles_ipocurve);
+ break;
+ case 2: /* vector */
+ ipo_keys_bezier_loop(ipo, set_bezier_vector, calchandles_ipocurve);
+ break;
+ default: /* free or align? */
+ if (ipo_keys_bezier_loop(ipo, bezier_isfree, NULL)) /* free */
+ ipo_keys_bezier_loop(ipo, set_bezier_free, calchandles_ipocurve);
+ else /* align */
+ ipo_keys_bezier_loop(ipo, set_bezier_align, calchandles_ipocurve);
+ break;
+ }
+}
+#endif
+
+/* ------- */
+
+void set_ipocurve_mixed(IpoCurve *icu)
+{
+ /* Sets the type of the IPO curve to mixed, as some (selected)
+ * keyframes were set to other interpolation modes
+ */
+ icu->ipo= IPO_MIXED;
+
+ /* recalculate handles, as some changes may have occurred */
+ calchandles_ipocurve(icu);
+}
+
+static short set_bezt_constant(Scene *scene, BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->ipo= IPO_CONST;
+ return 0;
+}
+
+static short set_bezt_linear(Scene *scene, BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->ipo= IPO_LIN;
+ return 0;
+}
+
+static short set_bezt_bezier(Scene *scene, BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ bezt->ipo= IPO_BEZ;
+ return 0;
+}
+
+/* Set the interpolation type of the selected BezTriples in each IPO curve to the specified one */
+// set_ipocurve_mixed() !
+BeztEditFunc ANIM_editkeyframes_ipo(short code)
+{
+ switch (code) {
+ case 1: /* constant */
+ return set_bezt_constant;
+ case 2: /* linear */
+ return set_bezt_linear;
+ default: /* bezier */
+ return set_bezt_bezier;
+ }
+}
+
+#if 0
+void setipotype_ipo(Ipo *ipo, int code)
+{
+ /* Sets the type of the selected bezts in each ipo curve in the
+ * Ipo to a value based on the code
+ */
+ switch (code) {
+ case 1:
+ ipo_keys_bezier_loop(ipo, set_bezt_constant, set_ipocurve_mixed);
+ break;
+ case 2:
+ ipo_keys_bezier_loop(ipo, set_bezt_linear, set_ipocurve_mixed);
+ break;
+ case 3:
+ ipo_keys_bezier_loop(ipo, set_bezt_bezier, set_ipocurve_mixed);
+ break;
+ }
+}
+#endif
+
+// XXX will we keep this?
+void setexprap_ipoloop(Ipo *ipo, int code)
+{
+ IpoCurve *icu;
+
+ /* Loop through each curve in the Ipo */
+ for (icu=ipo->curve.first; icu; icu=icu->next)
+ icu->extrap= code;
+}
+
+/* ******************************************* */
+/* Selection */
+
+static short select_bezier_add(Scene *scene, BezTriple *bezt)
+{
+ /* Select the bezier triple */
+ BEZ_SEL(bezt);
+ return 0;
+}
+
+static short select_bezier_subtract(Scene *scene, BezTriple *bezt)
+{
+ /* Deselect the bezier triple */
+ BEZ_DESEL(bezt);
+ return 0;
+}
+
+static short select_bezier_invert(Scene *scene, BezTriple *bezt)
+{
+ /* Invert the selection for the bezier triple */
+ bezt->f2 ^= SELECT;
+ if (bezt->f2 & SELECT) {
+ bezt->f1 |= SELECT;
+ bezt->f3 |= SELECT;
+ }
+ else {
+ bezt->f1 &= ~SELECT;
+ bezt->f3 &= ~SELECT;
+ }
+ return 0;
+}
+
+// NULL
+BeztEditFunc ANIM_editkeyframes_select(short selectmode)
+{
+ switch (selectmode) {
+ case SELECT_ADD: /* add */
+ return select_bezier_add;
+ case SELECT_SUBTRACT: /* subtract */
+ return select_bezier_subtract;
+ case SELECT_INVERT: /* invert */
+ return select_bezier_invert;
+ default: /* replace (need to clear all, then add) */
+ return select_bezier_add;
+ }
+}
+
+
+short is_ipo_key_selected(Ipo *ipo)
+{
+ IpoCurve *icu;
+ BezTriple *bezt;
+ int i;
+
+ if (ipo == NULL)
+ return 0;
+
+ for (icu=ipo->curve.first; icu; icu=icu->next) {
+ for (i=0, bezt=icu->bezt; i<icu->totvert; i++, bezt++) {
+ if (BEZSELECTED(bezt))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+void set_ipo_key_selection(Ipo *ipo, short sel)
+{
+ IpoCurve *icu;
+ BezTriple *bezt;
+ int i;
+
+ if (ipo == NULL)
+ return;
+
+ for (icu=ipo->curve.first; icu; icu=icu->next) {
+ for (i=0, bezt=icu->bezt; i<icu->totvert; i++, bezt++) {
+ if (sel == 2) {
+ BEZ_INVSEL(bezt);
+ }
+ else if (sel == 1) {
+ BEZ_SEL(bezt);
+ }
+ else {
+ BEZ_DESEL(bezt);
+ }
+ }
+ }
+}
+
+// err... this is this still used?
+int fullselect_ipo_keys(Ipo *ipo)
+{
+ IpoCurve *icu;
+ int tvtot = 0;
+ int i;
+
+ if (!ipo)
+ return tvtot;
+
+ for (icu=ipo->curve.first; icu; icu=icu->next) {
+ for (i=0; i<icu->totvert; i++) {
+ if (icu->bezt[i].f2 & SELECT) {
+ tvtot+=3;
+ icu->bezt[i].f1 |= SELECT;
+ icu->bezt[i].f3 |= SELECT;
+ }
+ }
+ }
+
+ return tvtot;
+}
+
+
+void borderselect_icu_key(Scene *scene, 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)) {
+ select_cb(scene, bezt);
+ }
+ }
+}
+
+void borderselect_ipo_key(Scene *scene, 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(scene, icu, xmin, xmax, select_cb);
+ }
+}
+
+
+#if 0
+void select_ipo_bezier_keys(Ipo *ipo, int selectmode)
+{
+ /* Select all of the beziers in all
+ * of the Ipo curves belonging to the
+ * Ipo, using the selection mode.
+ */
+ switch (selectmode) {
+ case SELECT_ADD:
+ ipo_keys_bezier_loop(ipo, select_bezier_add, NULL);
+ break;
+ case SELECT_SUBTRACT:
+ ipo_keys_bezier_loop(ipo, select_bezier_subtract, NULL);
+ break;
+ case SELECT_INVERT:
+ ipo_keys_bezier_loop(ipo, select_bezier_invert, NULL);
+ break;
+ }
+}
+
+void select_icu_bezier_keys(IpoCurve *icu, int selectmode)
+{
+ /* Select all of the beziers in all
+ * of the Ipo curves belonging to the
+ * Ipo, using the selection mode.
+ */
+ switch (selectmode) {
+ case SELECT_ADD:
+ icu_keys_bezier_loop(icu, select_bezier_add, NULL);
+ break;
+ case SELECT_SUBTRACT:
+ icu_keys_bezier_loop(icu, select_bezier_subtract, NULL);
+ break;
+ case SELECT_INVERT:
+ icu_keys_bezier_loop(icu, select_bezier_invert, NULL);
+ break;
+ }
+}
+#endif
+
+void select_icu_key(Scene *scene, 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(scene, bezt);
+ }
+ }
+}
+
+void select_ipo_key(Scene *scene, 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(scene, bezt);
+ }
+ }
+ }
+}
+
+