diff options
Diffstat (limited to 'source/blender/src/editaction.c')
-rw-r--r-- | source/blender/src/editaction.c | 1414 |
1 files changed, 1414 insertions, 0 deletions
diff --git a/source/blender/src/editaction.c b/source/blender/src/editaction.c new file mode 100644 index 00000000000..f927bcf5264 --- /dev/null +++ b/source/blender/src/editaction.c @@ -0,0 +1,1414 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL 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. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * 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): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include <string.h> +#include <math.h> + +#ifdef WIN32 +#include "BLI_winstuff.h" +#endif + +#include "MEM_guardedalloc.h" + +#include "PIL_time.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_curve_types.h" +#include "DNA_ipo_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_userdef_types.h" +#include "DNA_constraint_types.h" + +#include "BKE_armature.h" +#include "BKE_constraint.h" +#include "BKE_displist.h" +#include "BKE_curve.h" +#include "BKE_ipo.h" +#include "BKE_global.h" +#include "BKE_library.h" +#include "BKE_main.h" +#include "BKE_action.h" + +#include "BIF_gl.h" +#include "BIF_mywindow.h" +#include "BIF_toolbox.h" +#include "BIF_screen.h" +#include "BIF_space.h" +#include "BIF_buttons.h" +#include "BIF_interface.h" +#include "BIF_editview.h" +#include "BIF_poseobject.h" +#include "BIF_editarmature.h" + +#include "BSE_edit.h" +#include "BSE_drawipo.h" +#include "BSE_headerbuttons.h" +#include "BSE_editipo.h" +#include "BSE_editaction.h" +#include "BSE_trans_types.h" +#include "BSE_editaction_types.h" + +#include "BDR_editobject.h" + +#include "blendertimer.h" + +#include "interface.h" +#include "mydevice.h" +#include "blendef.h" +#include "nla.h" + +static bPose *g_posebuf=NULL; +extern int count_action_levels (bAction *act); + +#define BEZSELECTED(bezt) (((bezt)->f1 & 1) || ((bezt)->f2 & 1) || ((bezt)->f3 & 1)) + +/* Local Function prototypes */ + +static void insertactionkey(bAction *act, bActionChannel *achan, bPoseChannel *chan, int adrcode, short makecurve, float time); +static void flip_name (char *name); +static void mouse_actionchannels(bAction *act, short *mval); +static void borderselect_action(void); +static void mouse_action(void); +static bActionChannel *get_nearest_actionchannel_key (float *index, short *sel, bConstraintChannel **conchan); +static void delete_actionchannels(void); +static void delete_actionchannel_keys(void); +static void duplicate_actionchannel_keys(void); +static void transform_actionchannel_keys(char mode); +static void select_poseelement_by_name (char *name, int select); +static void hilight_channel (bAction *act, bActionChannel *chan, short hilight); +static void set_action_key_time (bAction *act, bPoseChannel *chan, int adrcode, short makecurve, float time); + +/* Implementation */ + +static void select_poseelement_by_name (char *name, int select) +{ + /* Synchs selection of channels with selection of object elements in posemode */ + + Object *ob; + + ob = G.obpose; + if (!ob) + return; + + switch (ob->type){ + case OB_ARMATURE: + select_bone_by_name ((bArmature*)ob->data, name, select); + break; + default: + break; + } +} +#ifdef __NLA_BAKE +bAction* bake_action_with_client (bAction *act, Object *armob, float tolerance) +{ + bAction *result=NULL; + bActionChannel *achan; + float actlen; + int curframe; + char newname[64]; + bArmature *arm; + Bone *bone; + float oldframe; + bAction *temp; + bPoseChannel *pchan; + + if (!act) + return NULL; + + arm = get_armature(armob); + + + if (G.obedit){ + error ("Not in editmode"); + return NULL; + } + + if (!arm){ + error ("Must have an armature selected"); + return NULL; + } + /* Get a new action */ + result = add_empty_action(); + + /* Assign the new action a unique name */ + sprintf (newname, "%s.BAKED", act->id.name+2); + rename_id(&result->id, newname); + + actlen = calc_action_end(act); + + oldframe = G.scene->r.cfra; + + temp = armob->action; + armob->action = act; + + for (curframe=1; curframe<ceil(actlen+1); curframe++){ + + /* Apply the old action */ + + G.scene->r.cfra = curframe; + + /* Apply the object ipo */ + get_pose_from_action(&armob->pose, act, curframe); + apply_pose_armature(arm, armob->pose, 1); + clear_object_constraint_status(armob); + where_is_armature_time(armob, curframe); + + /* For each channel: set avail keys with current values */ + for (pchan=armob->pose->chanbase.first; pchan; pchan=pchan->next){ + + /* Copy the constraints from the armature (if any) */ + + bone = get_named_bone(arm, pchan->name); + if (bone){ + + Mat4ToQuat(pchan->obmat, pchan->quat); + Mat4ToSize(pchan->obmat, pchan->size); + VECCOPY(pchan->loc, pchan->obmat[3]); + + /* Apply to keys */ + set_action_key_time (result, pchan, AC_QUAT_X, 1, curframe); + set_action_key_time (result, pchan, AC_QUAT_Y, 1, curframe); + set_action_key_time (result, pchan, AC_QUAT_Z, 1, curframe); + set_action_key_time (result, pchan, AC_QUAT_W, 1, curframe); + set_action_key_time (result, pchan, AC_LOC_X, 1, curframe); + set_action_key_time (result, pchan, AC_LOC_Y, 1, curframe); + set_action_key_time (result, pchan, AC_LOC_Z, 1, curframe); + } + } + } + + /* Make another pass to ensure all keyframes are set to linear interpolation mode */ + for (achan = result->chanbase.first; achan; achan=achan->next){ + IpoCurve* icu; + for (icu = achan->ipo->curve.first; icu; icu=icu->next){ + icu->ipo= IPO_LIN; + } + } + + notice ("Made new action \"%s\"", newname); + G.scene->r.cfra = oldframe; + armob->action = temp; + return result; +} +#endif + +void select_actionchannel_by_name (bAction *act, char *name, int select) +{ + bActionChannel *chan; + + if (!act) + return; + + for (chan = act->chanbase.first; chan; chan=chan->next){ + if (!strcmp (chan->name, name)){ + act->achan = chan; + if (select){ + chan->flag |= ACHAN_SELECTED; + hilight_channel (act, chan, 1); + } + else{ + chan->flag &= ~ACHAN_SELECTED; + hilight_channel (act, chan, 0); + } + return; + } + } +} + +void remake_action_ipos(bAction *act) +{ + bActionChannel *chan; + bConstraintChannel *conchan; + IpoCurve *icu; + + for (chan= act->chanbase.first; chan; chan=chan->next){ + if (chan->ipo){ + for (icu = chan->ipo->curve.first; icu; icu=icu->next){ + sort_time_ipocurve(icu); + testhandles_ipocurve(icu); + } + } + for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){ + if (conchan->ipo){ + for (icu = conchan->ipo->curve.first; icu; icu=icu->next){ + sort_time_ipocurve(icu); + testhandles_ipocurve(icu); + } + } + } + } +} + +static void duplicate_actionchannel_keys(void) +{ + bAction *act; + bActionChannel *chan; + bConstraintChannel *conchan; + + act=G.saction->action; + if (!act) + return; + + /* Find selected items */ + for (chan = act->chanbase.first; chan; chan=chan->next){ + duplicate_ipo_keys(chan->ipo); + for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) + duplicate_ipo_keys(conchan->ipo); + } + + transform_actionchannel_keys ('g'); +} + +static bActionChannel *get_nearest_actionchannel_key (float *index, short *sel, bConstraintChannel **rchan){ + bAction *act; + bActionChannel *chan; + IpoCurve *icu; + bActionChannel *firstchan=NULL; + bConstraintChannel *conchan, *firstconchan=NULL; + int foundsel=0; + float firstvert=-1, foundx=-1; + int i; + short mval[2]; + float ymin, ymax; + rctf rectf; + *index=0; + + *rchan=NULL; + act=G.saction->action; /* We presume that we are only called during a valid action */ + + getmouseco_areawin (mval); + + mval[0]-=7; + areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin); + + mval[0]+=14; + areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax); + + ymax = count_action_levels (act) * (CHANNELHEIGHT + CHANNELSKIP); + + *sel=0; + + for (chan=act->chanbase.first; chan; chan=chan->next){ + + /* Check action channel */ + ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP); + if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){ + for (icu=chan->ipo->curve.first; icu; icu=icu->next){ + for (i=0; i<icu->totvert; i++){ + if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){ + if (!firstchan){ + firstchan=chan; + firstvert=icu->bezt[i].vec[1][0]; + *sel = icu->bezt[i].f2 & 1; + } + + if (icu->bezt[i].f2 & 1){ + if (!foundsel){ + foundsel=1; + foundx = icu->bezt[i].vec[1][0]; + } + } + else if (foundsel && icu->bezt[i].vec[1][0] != foundx){ + *index=icu->bezt[i].vec[1][0]; + *sel = 0; + return chan; + } + } + } + } + } + ymax=ymin; + + /* Check constraint channels */ + for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){ + ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP); + if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){ + for (icu=conchan->ipo->curve.first; icu; icu=icu->next){ + for (i=0; i<icu->totvert; i++){ + if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){ + if (!firstchan){ + firstchan=chan; + firstconchan=conchan; + firstvert=icu->bezt[i].vec[1][0]; + *sel = icu->bezt[i].f2 & 1; + } + + if (icu->bezt[i].f2 & 1){ + if (!foundsel){ + foundsel=1; + foundx = icu->bezt[i].vec[1][0]; + } + } + else if (foundsel && icu->bezt[i].vec[1][0] != foundx){ + *index=icu->bezt[i].vec[1][0]; + *sel = 0; + *rchan = conchan; + return chan; + } + } + } + } + } + ymax=ymin; + } + } + + *rchan = firstconchan; + *index=firstvert; + return firstchan; +} + +static void mouse_action(void) +{ + bAction *act; + short sel; + float selx; + bActionChannel *chan; + bConstraintChannel *conchan; + short mval[2]; + + act=G.saction->action; + if (!act) + return; + + getmouseco_areawin (mval); + + chan=get_nearest_actionchannel_key(&selx, &sel, &conchan); + + if (chan){ + if (!(G.qual & LR_SHIFTKEY)){ + deselect_actionchannel_keys(act, 0); + deselect_actionchannels(act, 0); + act->achan = chan; + chan->flag |= ACHAN_SELECTED; + hilight_channel (act, chan, 1); + sel = 0; + } + + if (conchan) + select_ipo_key(conchan->ipo, selx, sel); + else + select_ipo_key(chan->ipo, selx, sel); + + allqueue(REDRAWIPO, 0); + allqueue(REDRAWVIEW3D, 0); + allqueue(REDRAWACTION, 0); + allqueue(REDRAWNLA, 0); + + } +} + +static void borderselect_action(void) +{ + rcti rect; + rctf rectf; + int val; + short mval[2]; + bActionChannel *chan; + bConstraintChannel *conchan; + bAction *act; + float ymin, ymax; + + act=G.saction->action; + val= get_border (&rect, 3); + + if (!act) + return; + + if (val){ + mval[0]= rect.xmin; + mval[1]= rect.ymin+2; + areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin); + mval[0]= rect.xmax; + mval[1]= rect.ymax-2; + areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax); + + ymax=count_action_levels(act) * (CHANNELHEIGHT+CHANNELSKIP); + for (chan=act->chanbase.first; chan; chan=chan->next){ + + /* Check action */ + ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP); + if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) + borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax, val); + + ymax=ymin; + + /* Check constraints */ + for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){ + ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP); + if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) + borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, val); + + ymax=ymin; + } + } + allqueue(REDRAWNLA, 0); + allqueue(REDRAWACTION, 0); + allqueue(REDRAWIPO, 0); + } +} + +bActionChannel* get_hilighted_action_channel(bAction* action) +{ + bActionChannel *chan; + + if (!action) + return NULL; + + for (chan=action->chanbase.first; chan; chan=chan->next){ + if (chan->flag & ACHAN_SELECTED && chan->flag & ACHAN_HILIGHTED) + return chan; + } + + return NULL; + +} + +void set_exprap_action(int mode) +{ + if(G.saction->action && G.saction->action->id.lib) return; + + error ("Not yet implemented!"); +} + +void free_posebuf(void) +{ + if (g_posebuf){ + clear_pose(g_posebuf); + MEM_freeN (g_posebuf); + } + g_posebuf=NULL; +} + +void copy_posebuf (void) +{ + Object *ob; + + free_posebuf(); + + ob=G.obpose; + if (!ob){ + error ("Copybuf is empty"); + return; + } + + filter_pose_keys(); + copy_pose(&g_posebuf, ob->pose, 0); + +} + +static void flip_name (char *name) +{ + + char prefix[128]={""}; /* The part before the facing */ + char suffix[128]={""}; /* The part after the facing */ + char replace[128]={""}; /* The replacement string */ + + char *index=NULL; + /* Find the last period */ + + strcpy (prefix, name); + + /* Check for an instance of .Right */ + if (!index){ + index = strstr (prefix, "Right"); + if (index){ + *index=0; + strcpy (replace, "Left"); + strcpy (suffix, index+6); + } + } + + /* Che ck for an instance of .RIGHT */ + if (!index){ + index = strstr (prefix, "RIGHT"); + if (index){ + *index=0; + strcpy (replace, "LEFT"); + strcpy (suffix, index+6); + } + } + + + /* Check for an instance of .right */ + if (!index){ + index = strstr (prefix, "right"); + if (index){ + *index=0; + strcpy (replace, "left"); + strcpy (suffix, index+6); + } + } + + /* Check for an instance of .left */ + if (!index){ + index = strstr (prefix, "left"); + if (index){ + *index=0; + strcpy (replace, "right"); + strcpy (suffix, index+5); + } + } + + /* Check for an instance of .LEFT */ + if (!index){ + index = strstr (prefix, "LEFT"); + if (index){ + *index=0; + strcpy (replace, "RIGHT"); + strcpy (suffix, index+5); + } + } + + /* Check for an instance of .Left */ + if (!index){ + index = strstr (prefix, "Left"); + if (index){ + *index=0; + strcpy (replace, "Right"); + strcpy (suffix, index+5); + } + } + + /* check for an instance of .L */ + if (!index){ + index = strstr (prefix, ".L"); + if (index){ + *index=0; + strcpy (replace, ".R"); + strcpy (suffix, index+2); + } + } + + /* check for an instance of .l */ + if (!index){ + index = strstr (prefix, ".l"); + if (index){ + *index=0; + strcpy (replace, ".r"); + strcpy (suffix, index+2); + } + } + + /* Checl for an instance of .R */ + if (!index){ + index = strstr (prefix, ".R"); + if (index){ + *index=0; + strcpy (replace, ".L"); + strcpy (suffix, index+2); + } + } + + /* Checl for an instance of .r */ + if (!index){ + index = strstr (prefix, ".r"); + if (index){ + *index=0; + strcpy (replace, ".l"); + strcpy (suffix, index+2); + } + } + + sprintf (name, "%s%s%s", prefix, replace, suffix); +} + +void paste_posebuf (int flip){ + Object *ob; + bPoseChannel *temp, *chan; + float eul[4]; + Base *base; + int newchan = 0; + + ob=G.obpose; + if (!ob) + return; + + if (!g_posebuf){ + error ("Copybuf is empty"); + return; + }; + + collect_pose_garbage(ob); + + /* Safely merge all of the channels in this pose into + any existing pose */ + if (ob->pose){ + if (U.flag & 0x01<<14){ + /* Display "Avail, all" dialog */ + } + for (chan=g_posebuf->chanbase.first; chan; chan=chan->next){ + if (chan->flag & POSE_KEY){ + temp = copy_pose_channel (chan); + if (flip){ + flip_name (temp->name); + temp->loc[0]*=-1; + + QuatToEul(temp->quat, eul); + eul[1]*=-1; + eul[2]*=-1; + EulToQuat(eul, temp->quat); + } + + temp = set_pose_channel (ob->pose, temp); + + if (U.flag & 0x01<<14){ + /* Set keys on pose */ + if (chan->flag & POSE_ROT){ + set_action_key(ob->action, temp, AC_QUAT_X, newchan); + set_action_key(ob->action, temp, AC_QUAT_Y, newchan); + set_action_key(ob->action, temp, AC_QUAT_Z, newchan); + set_action_key(ob->action, temp, AC_QUAT_W, newchan); + }; + if (chan->flag & POSE_SIZE){ + set_action_key(ob->action, temp, AC_SIZE_X, newchan); + set_action_key(ob->action, temp, AC_SIZE_Y, newchan); + set_action_key(ob->action, temp, AC_SIZE_Z, newchan); + }; + if (chan->flag & POSE_LOC){ + set_action_key(ob->action, temp, AC_LOC_X, newchan); + set_action_key(ob->action, temp, AC_LOC_Y, newchan); + set_action_key(ob->action, temp, AC_LOC_Z, newchan); + }; + } + } + } + + if (U.flag & 0x01<<14){ + remake_action_ipos(ob->action); + allqueue (REDRAWIPO, 0); + allqueue (REDRAWVIEW3D, 0); + allqueue (REDRAWACTION, 0); + allqueue(REDRAWNLA, 0); + } + + /* Update deformation children */ + if (G.obpose->type == OB_ARMATURE){ + for (base= FIRSTBASE; base; base= base->next){ + if (G.obpose==base->object->parent){ + if (base->object->partype==PARSKEL) + makeDispList(base->object); + } + } + } + } +} + +void set_action_key (struct bAction *act, struct bPoseChannel *chan, int adrcode, short makecurve) +{ + set_action_key_time (act, chan, adrcode, makecurve, frame_to_float(CFRA)); +} + +static void set_action_key_time (bAction *act, bPoseChannel *chan, int adrcode, short makecurve, float time) +{ + bActionChannel *achan; + char ipstr[256]; + + if (!act) + return; + + if (!chan) + return; + /* See if this action channel exists already */ + for (achan=act->chanbase.first; achan; achan=achan->next){ + if (!strcmp (chan->name, achan->name)) + break; + } + + if (!achan){ + if (!makecurve) + return; + achan = MEM_callocN (sizeof(bActionChannel), "actionChannel"); + strcpy (achan->name, chan->name); + BLI_addtail (&act->chanbase, achan); + } + + /* Ensure the channel appears selected in the action window */ + achan->flag |= ACHAN_SELECTED; + + /* Ensure this action channel has a valid Ipo */ + if (!achan->ipo){ + sprintf (ipstr, "%s.%s", act->id.name+2, chan->name); + ipstr[23]=0; + achan->ipo= add_ipo(ipstr, ID_AC); + } + + insertactionkey(act, achan, chan, adrcode, makecurve, time); + +} + +static void insertactionkey(bAction *act, bActionChannel *achan, bPoseChannel *chan, int adrcode, short makecurve, float cfra) +{ + IpoCurve *icu; + void *poin; + float curval; + int type; + ID *id; + + if (!act){ + return; + } + if (act->id.lib){ + error ("Can't pose libactions"); + return; + } + act->achan=achan; + act->pchan=chan; + + id=(ID*) act; + + /* First see if this curve exists */ + if (!makecurve){ + if (!achan->ipo) + return; + + for (icu = achan->ipo->curve.first; icu; icu=icu->next){ + if (icu->adrcode == adrcode) + break; + } + if (!icu) + return; + } + + + icu = get_ipocurve (id, GS(id->name), adrcode, achan->ipo); + + if(icu) { + poin= get_ipo_poin(id, icu, &type); + if(poin) { + curval= read_ipo_poin(poin, type); + // cfra= frame_to_float(CFRA); + insert_vert_ipo(icu, cfra, curval); + } + } + +} + +bAction *add_empty_action(void) +{ + bAction *act; + + act= alloc_libblock(&G.main->action, ID_AC, "Action"); + act->id.flag |= LIB_FAKEUSER; + act->id.us++; + return act; +} + +static void transform_actionchannel_keys(char mode) +{ + bAction *act; + TransVert *tv; + int /*sel=0,*/ i; + bActionChannel *chan; + short mvals[2], mvalc[2], cent[2]; + float sval[2], cval[2], lastcval[2]; + short cancel=0; + float fac=0.0F; + int loop=1; + int tvtot=0; + float deltax, startx; + float cenf[2]; + int invert=0, firsttime=1; + char str[256]; + bConstraintChannel *conchan; + + act=G.saction->action; + + /* Ensure that partial selections result in beztriple selections */ + for (chan=act->chanbase.first; chan; chan=chan->next){ + tvtot+=fullselect_ipo_keys(chan->ipo); + + for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) + tvtot+=fullselect_ipo_keys(conchan->ipo); + } + + /* If nothing is selected, bail out */ + if (!tvtot) + return; + + + /* Build the transvert structure */ + tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert"); + tvtot=0; + for (chan=act->chanbase.first; chan; chan=chan->next){ + /* Add the actionchannel */ + tvtot = add_trans_ipo_keys(chan->ipo, tv, tvtot); + for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) + tvtot = add_trans_ipo_keys(conchan->ipo, tv, tvtot); + } + + /* Do the event loop */ + cent[0] = curarea->winx + (G.saction->v2d.hor.xmax)/2; + cent[1] = curarea->winy + (G.saction->v2d.hor.ymax)/2; + areamouseco_to_ipoco(G.v2d, cent, &cenf[0], &cenf[1]); + + getmouseco_areawin (mvals); + areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]); + + startx=sval[0]; + while (loop) { + /* Get the input */ + /* If we're cancelling, reset transformations */ + /* Else calc new transformation */ + /* Perform the transformations */ + while (qtest()) { + short val; + unsigned short event= extern_qread(&val); + + if (val) { + switch (event) { + case LEFTMOUSE: + case SPACEKEY: + case RETKEY: + loop=0; + break; + case XKEY: + break; + case ESCKEY: + case RIGHTMOUSE: + cancel=1; + loop=0; + break; + default: + arrows_move_cursor(event); + break; + }; + } + } + + if (cancel) { + for (i=0; i<tvtot; i++) { + tv[i].loc[0]=tv[i].oldloc[0]; + tv[i].loc[1]=tv[i].oldloc[1]; + } + } else { + getmouseco_areawin (mvalc); + areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]); + + if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) { + PIL_sleep_ms(1); + } else { + for (i=0; i<tvtot; i++){ + tv[i].loc[0]=tv[i].oldloc[0]; + + switch (mode){ + case 'g': + deltax = cval[0]-sval[0]; + fac= deltax; + + apply_keyb_grid(&fac, 0.0, 1.0, 0.1, U.flag & AUTOGRABGRID); + + tv[i].loc[0]+=fac; + break; + case 's': + startx=mvals[0]-(ACTWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2); + deltax=mvalc[0]-(ACTWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2); + fac= fabs(deltax/startx); + + apply_keyb_grid(&fac, 0.0, 0.2, 0.1, U.flag & AUTOSIZEGRID); + + if (invert){ + if (i % 03 == 0){ + memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i+2].oldloc)); + } + if (i % 03 == 2){ + memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i-2].oldloc)); + } + + fac*=-1; + } + startx= (G.scene->r.cfra); + + tv[i].loc[0]-= startx; + tv[i].loc[0]*=fac; + tv[i].loc[0]+= startx; + + break; + } + } + } + + if (mode=='s'){ + sprintf(str, "sizeX: %.3f", fac); + headerprint(str); + } + else if (mode=='g'){ + sprintf(str, "deltaX: %.3f", fac); + headerprint(str); + } + + if (G.saction->lock){ + do_all_actions(); + allqueue (REDRAWVIEW3D, 0); + allqueue (REDRAWACTION, 0); + allqueue (REDRAWIPO, 0); + allqueue(REDRAWNLA, 0); + force_draw_all(); + } + else { + addqueue (curarea->win, REDRAWALL, 0); + force_draw (); + } + } + + lastcval[0]= cval[0]; + lastcval[1]= cval[1]; + firsttime= 0; + } + + /* Update the curve */ + /* Depending on the lock status, draw necessary views */ + + do_all_actions(); + remake_action_ipos(act); + allqueue (REDRAWVIEW3D, 0); + allqueue (REDRAWACTION, 0); + allqueue(REDRAWNLA, 0); + allqueue (REDRAWIPO, 0); + MEM_freeN (tv); +} + +void deselect_actionchannel_keys (bAction *act, int test) +{ + bActionChannel *chan; + bConstraintChannel *conchan; + int sel=1;; + + if (!act) + return; + + /* Determine if this is selection or deselection */ + + if (test){ + for (chan=act->chanbase.first; chan; chan=chan->next){ + /* Test the channel ipos */ + if (is_ipo_key_selected(chan->ipo)){ + sel = 0; + break; + } + + /* Test the constraint ipos */ + for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){ + if (is_ipo_key_selected(conchan->ipo)){ + sel = 0; + break; + } + } + + if (sel == 0) + break; + } + } + else + sel=0; + + /* Set the flags */ + for (chan=act->chanbase.first; chan; chan=chan->next){ + set_ipo_key_selection(chan->ipo, sel); + for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) + set_ipo_key_selection(conchan->ipo, sel); + } +} + +void deselect_actionchannels (bAction *act, int test) +{ + bActionChannel *chan; + bConstraintChannel *conchan; + int sel=1; + + if (!act) + return; + + /* See if we should be selecting or deselecting */ + if (test){ + for (chan=act->chanbase.first; chan; chan=chan->next){ + if (!sel) + break; + + if (chan->flag & ACHAN_SELECTED){ + sel=0; + break; + } + if (sel){ + for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){ + if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){ + sel=0; + break; + } + } + } + } + } + else + sel=0; + + /* Now set the flags */ + for (chan=act->chanbase.first; chan; chan=chan->next){ + select_poseelement_by_name(chan->name, sel); + + if (sel) + chan->flag |= ACHAN_SELECTED; + else + chan->flag &= ~ACHAN_SELECTED; + + for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){ + if (sel) + conchan->flag |= CONSTRAINT_CHANNEL_SELECT; + else + conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT; + } + } + +} + +static void hilight_channel (bAction *act, bActionChannel *chan, short select) +{ + bActionChannel *curchan; + + if (!act) + return; + + for (curchan=act->chanbase.first; curchan; curchan=curchan->next){ + if (curchan==chan && select) + curchan->flag |= ACHAN_HILIGHTED; + else + curchan->flag &= ~ACHAN_HILIGHTED; + } +} + +static void mouse_actionchannels(bAction *act, short *mval) +{ + bActionChannel *chan; + bConstraintChannel *clickconchan=NULL; + float click; + int wsize; + int sel; + bConstraintChannel *conchan; + + if (!act) + return; + + wsize = (count_action_levels (act)*(CHANNELHEIGHT+CHANNELSKIP)); + + + click = (wsize-(mval[1]+G.v2d->cur.ymin)); + click += CHANNELHEIGHT/2; + click /= (CHANNELHEIGHT+CHANNELSKIP); + + if (click<0) + return; + + for (chan = act->chanbase.first; chan; chan=chan->next){ + if ((int)click==0) + break; + + click--; + + /* Check for click in a constraint */ + for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){ + if ((int)click==0){ + clickconchan=conchan; + chan=act->chanbase.last; + break; + } + click--; + } + } + + if (!chan){ + if (clickconchan){ + if (clickconchan->flag & CONSTRAINT_CHANNEL_SELECT) + sel = 0; + else + sel =1; + + /* Channel names clicking */ + if (G.qual & LR_SHIFTKEY){ + // select_poseelement_by_name(chan->name, !(chan->flag & ACHAN_SELECTED)); + if (clickconchan->flag & CONSTRAINT_CHANNEL_SELECT){ + clickconchan->flag &= ~CONSTRAINT_CHANNEL_SELECT; + // hilight_channel(act, chan, 0); + } + else{ + clickconchan->flag |= CONSTRAINT_CHANNEL_SELECT; + // hilight_channel(act, chan, 1); + } + } + else{ + deselect_actionchannels (act, 0); // Auto clear + clickconchan->flag |= CONSTRAINT_CHANNEL_SELECT; + // hilight_channel(act, chan, 1); + // act->achan = chan; + // select_poseelement_by_name(chan->name, 1); + } + + } + else + return; + } + else{ + /* Choose the mode */ + if (chan->flag & ACHAN_SELECTED) + sel = 0; + else + sel =1; + + /* Channel names clicking */ + if (G.qual & LR_SHIFTKEY){ + select_poseelement_by_name(chan->name, !(chan->flag & ACHAN_SELECTED)); + if (chan->flag & ACHAN_SELECTED){ + chan->flag &= ~ACHAN_SELECTED; + hilight_channel(act, chan, 0); + } + else{ + chan->flag |= ACHAN_SELECTED; + hilight_channel(act, chan, 1); + } + } + else{ + deselect_actionchannels (act, 0); // Auto clear + chan->flag |= ACHAN_SELECTED; + hilight_channel(act, chan, 1); + act->achan = chan; + select_poseelement_by_name(chan->name, 1); + } + + } + allqueue (REDRAWIPO, 0); + allqueue (REDRAWVIEW3D, 0); + allqueue (REDRAWACTION, 0); + allqueue(REDRAWNLA, 0); + +} + +static void delete_actionchannel_keys(void) +{ + bAction *act; + bActionChannel *chan; + bConstraintChannel *conchan; + + act = G.saction->action; + if (!act) + return; + + if (!okee("Erase selected keys")) + return; + + for (chan = act->chanbase.first; chan; chan=chan->next){ + + /* Check action channel keys*/ + delete_ipo_keys(chan->ipo); + + /* Delete constraint channel keys */ + for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) + delete_ipo_keys(conchan->ipo); + } + + remake_action_ipos (act); + allspace(REMAKEIPO, 0); + allqueue(REDRAWACTION, 0); + allqueue(REDRAWIPO, 0); + allqueue(REDRAWNLA, 0); + +} +static void delete_actionchannels (void) +{ + bConstraintChannel *conchan, *nextconchan; + bActionChannel *chan, *next; + bAction *act; + int freechan; + + act=G.saction->action; + + if (!act) + return; + + for (chan=act->chanbase.first; chan; chan=chan->next){ + if (chan->flag & ACHAN_SELECTED) + break; + for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) + { + if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){ + chan=act->chanbase.last; + break; + } + } + } + + if (!chan && !conchan) + return; + + if (!okee("Erase selected channels")) + return; + + for (chan=act->chanbase.first; chan; chan=next){ + freechan = 0; + next=chan->next; + + /* Remove action channels */ + if (chan->flag & ACHAN_SELECTED){ + if (chan->ipo) + chan->ipo->id.us--; /* Release the ipo */ + freechan = 1; + } + + /* Remove constraint channels */ + for (conchan=chan->constraintChannels.first; conchan; conchan=nextconchan){ + nextconchan=conchan->next; + if (freechan || conchan->flag & CONSTRAINT_CHANNEL_SELECT){ + if (conchan->ipo) + conchan->ipo->id.us--; + BLI_freelinkN(&chan->constraintChannels, conchan); + } + } + + if (freechan) + BLI_freelinkN (&act->chanbase, chan); + + } + + allqueue (REDRAWACTION, 0); + allqueue(REDRAWNLA, 0); + +} +void winqreadactionspace(unsigned short event, short val, char ascii) +{ + SpaceAction *saction; + bAction *act; + int doredraw= 0; + short mval[2]; + float dx,dy; + int cfra; + + if(curarea->win==0) return; + + saction= curarea->spacedata.first; + if (!saction) + return; + + act=saction->action; + if(val) { + + if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0; + + getmouseco_areawin(mval); + + switch(event) { + case UI_BUT_EVENT: + do_blenderbuttons(val); + break; + case HOMEKEY: + do_action_buttons(B_ACTHOME); + break; + case DKEY: + if (G.qual & LR_SHIFTKEY && mval[0]>ACTWIDTH){ + duplicate_actionchannel_keys(); + remake_action_ipos(act); + } + break; + case DELKEY: + case XKEY: + if (mval[0]<ACTWIDTH) + delete_actionchannels (); + else + delete_actionchannel_keys (); + break; + case GKEY: + if (mval[0]>=ACTWIDTH) + transform_actionchannel_keys ('g'); + break; + case SKEY: + if (mval[0]>=ACTWIDTH) + transform_actionchannel_keys ('s'); + break; + case AKEY: + if (mval[0]<ACTWIDTH){ + deselect_actionchannels (act, 1); + allqueue (REDRAWVIEW3D, 0); + allqueue (REDRAWACTION, 0); + allqueue(REDRAWNLA, 0); + allqueue (REDRAWIPO, 0); + } + else{ + deselect_actionchannel_keys (act, 1); + allqueue (REDRAWACTION, 0); + allqueue(REDRAWNLA, 0); + allqueue (REDRAWIPO, 0); + } + break; + case BKEY: + borderselect_action(); + break; + case RIGHTMOUSE: + if (mval[0]<ACTWIDTH) + mouse_actionchannels(act, mval); + else + mouse_action(); + break; + case LEFTMOUSE: + if (mval[0]>ACTWIDTH){ + do { + getmouseco_areawin(mval); + + areamouseco_to_ipoco(G.v2d, mval, &dx, &dy); + + cfra= (int)dx; + if(cfra< 1) cfra= 1; + + if( cfra!=CFRA ) { + CFRA= cfra; + update_for_newframe(); + force_draw_plus(SPACE_VIEW3D); + force_draw_plus(SPACE_IPO); + force_draw_plus(SPACE_BUTS); + } + + } while(get_mbut()&L_MOUSE); + } + + break; + case MIDDLEMOUSE: + view2dmove(); /* in drawipo.c */ + break; + } + } + + if(doredraw) addqueue(curarea->win, REDRAW, 1); + +} + |