4 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version. The Blender
10 * Foundation also sells licenses for use in proprietary software under
11 * the Blender License. See http://www.blender.org/BL/ for information
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24 * All rights reserved.
26 * The Original Code is: all of this file.
28 * Contributor(s): none yet.
30 * ***** END GPL/BL DUAL LICENSE BLOCK *****
40 #include "MEM_guardedalloc.h"
44 #include "BLI_blenlib.h"
45 #include "BLI_arithb.h"
47 #include "DNA_action_types.h"
48 #include "DNA_armature_types.h"
49 #include "DNA_curve_types.h"
50 #include "DNA_ipo_types.h"
51 #include "DNA_object_types.h"
52 #include "DNA_scene_types.h"
53 #include "DNA_screen_types.h"
54 #include "DNA_userdef_types.h"
55 #include "DNA_constraint_types.h"
56 #include "DNA_key_types.h"
57 #include "DNA_mesh_types.h"
58 #include "DNA_nla_types.h"
59 #include "DNA_lattice_types.h"
61 #include "BKE_action.h"
62 #include "BKE_armature.h"
63 #include "BKE_constraint.h"
64 #include "BKE_curve.h"
65 #include "BKE_depsgraph.h"
66 #include "BKE_global.h"
69 #include "BKE_library.h"
71 #include "BKE_utildefines.h"
73 #include "BIF_butspace.h"
74 #include "BIF_editaction.h"
75 #include "BIF_editview.h"
76 #include "BIF_editarmature.h"
78 #include "BIF_interface.h"
79 #include "BIF_mywindow.h"
80 #include "BIF_poseobject.h"
81 #include "BIF_screen.h"
82 #include "BIF_space.h"
83 #include "BIF_toolbox.h"
86 #include "BSE_drawipo.h"
87 #include "BSE_headerbuttons.h"
88 #include "BSE_editipo.h"
89 #include "BSE_trans_types.h"
91 #include "BDR_editobject.h"
97 extern int count_action_levels (bAction *act);
99 #define BEZSELECTED(bezt) (((bezt)->f1 & 1) || ((bezt)->f2 & 1) || ((bezt)->f3 & 1))
101 /* Local Function prototypes, are forward needed */
102 static void hilight_channel (bAction *act, bActionChannel *chan, short hilight);
104 static void up_sel_action(void);
105 static void down_sel_action(void);
106 static void top_sel_action(void);
107 static void bottom_sel_action(void);
111 short showsliders = 0;
112 short ACTWIDTH = NAMEWIDTH;
114 static void select_poseelement_by_name (char *name, int select)
116 /* Synchs selection of channels with selection of object elements in posemode */
125 select_bone_by_name ((bArmature*)ob->data, name, select);
132 bAction* bake_action_with_client (bAction *act, Object *armob, float tolerance)
135 bAction *result=NULL;
136 bActionChannel *achan;
148 arm = get_armature(armob);
151 error ("Actions can't be baked in Edit Mode");
155 if (!arm || armob->pose==NULL){
156 error ("Select an armature before baking");
160 /* Get a new action */
161 result = add_empty_action(ID_PO);
164 /* Assign the new action a unique name */
165 sprintf (newname, "%s.BAKED", act->id.name+2);
166 rename_id(&result->id, newname);
168 actlen = calc_action_end(act);
170 oldframe = G.scene->r.cfra;
172 temp = armob->action;
173 armob->action = result;
175 for (curframe=1; curframe<ceil(actlen+1); curframe++){
177 /* Apply the old action */
179 G.scene->r.cfra = curframe;
181 /* Apply the object ipo */
182 extract_pose_from_action(armob->pose, act, curframe);
184 where_is_pose(armob);
186 /* For each channel: set quats and locs if channel is a bone */
187 for (pchan=armob->pose->chanbase.first; pchan; pchan=pchan->next){
190 insertkey(id, ID_AC, pchan->name, NULL, AC_LOC_X);
191 insertkey(id, ID_AC, pchan->name, NULL, AC_LOC_Y);
192 insertkey(id, ID_AC, pchan->name, NULL, AC_LOC_Z);
193 insertkey(id, ID_AC, pchan->name, NULL, AC_QUAT_X);
194 insertkey(id, ID_AC, pchan->name, NULL, AC_QUAT_Y);
195 insertkey(id, ID_AC, pchan->name, NULL, AC_QUAT_Z);
196 insertkey(id, ID_AC, pchan->name, NULL, AC_QUAT_W);
197 insertkey(id, ID_AC, pchan->name, NULL, AC_SIZE_X);
198 insertkey(id, ID_AC, pchan->name, NULL, AC_SIZE_Y);
199 insertkey(id, ID_AC, pchan->name, NULL, AC_SIZE_Z);
204 /* Make another pass to ensure all keyframes are set to linear interpolation mode */
205 for (achan = result->chanbase.first; achan; achan=achan->next){
208 for (icu = achan->ipo->curve.first; icu; icu=icu->next){
214 notice ("Made a new action named \"%s\"", newname);
215 G.scene->r.cfra = oldframe;
216 armob->action = temp;
219 extract_pose_from_action(armob->pose, act, G.scene->r.cfra);
220 where_is_pose(armob);
222 allqueue(REDRAWACTION, 1);
227 /* apparently within active object context */
228 void select_actionchannel_by_name (bAction *act, char *name, int select)
230 bActionChannel *chan;
235 for (chan = act->chanbase.first; chan; chan=chan->next){
236 if (!strcmp (chan->name, name)){
238 chan->flag |= ACHAN_SELECTED;
239 hilight_channel (act, chan, 1);
240 select_poseelement_by_name(chan->name, 1);
243 chan->flag &= ~ACHAN_SELECTED;
244 hilight_channel (act, chan, 0);
245 select_poseelement_by_name(chan->name, 0);
252 void remake_action_ipos(bAction *act)
254 bActionChannel *chan;
255 bConstraintChannel *conchan;
258 for (chan= act->chanbase.first; chan; chan=chan->next){
260 for (icu = chan->ipo->curve.first; icu; icu=icu->next){
261 sort_time_ipocurve(icu);
262 testhandles_ipocurve(icu);
265 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
267 for (icu = conchan->ipo->curve.first; icu; icu=icu->next){
268 sort_time_ipocurve(icu);
269 testhandles_ipocurve(icu);
276 static void remake_meshaction_ipos(Ipo *ipo)
278 /* this puts the bezier triples in proper
279 * order and makes sure the bezier handles
280 * aren't too strange.
284 for (icu = ipo->curve.first; icu; icu=icu->next){
285 sort_time_ipocurve(icu);
286 testhandles_ipocurve(icu);
290 static void meshkey_do_redraw(Key *key)
292 remake_meshaction_ipos(key->ipo);
294 DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
296 allspace(REMAKEIPO, 0);
297 allqueue(REDRAWACTION, 0);
298 allqueue(REDRAWIPO, 0);
299 allqueue(REDRAWNLA, 0);
303 void duplicate_meshchannel_keys(Key *key)
305 duplicate_ipo_keys(key->ipo);
306 transform_meshchannel_keys ('g', key);
310 void duplicate_actionchannel_keys(void)
313 bActionChannel *chan;
314 bConstraintChannel *conchan;
316 act=G.saction->action;
320 /* Find selected items */
321 for (chan = act->chanbase.first; chan; chan=chan->next){
322 duplicate_ipo_keys(chan->ipo);
323 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
324 duplicate_ipo_keys(conchan->ipo);
327 transform_actionchannel_keys ('g', 0);
330 static bActionChannel *get_nearest_actionchannel_key (float *index, short *sel, bConstraintChannel **rchan)
333 bActionChannel *chan;
335 bActionChannel *firstchan=NULL;
336 bConstraintChannel *conchan, *firstconchan=NULL;
338 float firstvert=-1, foundx=-1;
339 float ymin, ymax, xmin, xmax;
347 act= G.saction->action; /* We presume that we are only called during a valid action */
349 getmouseco_areawin (mval);
352 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
354 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
356 ymax = count_action_levels(act) * (CHANNELHEIGHT + CHANNELSKIP);
357 ymax += CHANNELHEIGHT/2;
359 /* if action is mapped in NLA, it returns a correction */
360 if(G.saction->pin==0 && OBACT) {
361 xmin= get_action_frame(OBACT, rectf.xmin);
362 xmax= get_action_frame(OBACT, rectf.xmax);
371 for (chan=act->chanbase.first; chan; chan=chan->next){
373 /* Check action channel */
374 ymin= ymax-(CHANNELHEIGHT+CHANNELSKIP);
375 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)) && chan->ipo){
376 for (icu=chan->ipo->curve.first; icu; icu=icu->next){
377 for (i=0; i<icu->totvert; i++){
378 if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] <= xmax ){
381 firstvert=icu->bezt[i].vec[1][0];
382 *sel = icu->bezt[i].f2 & 1;
385 if (icu->bezt[i].f2 & 1){
388 foundx = icu->bezt[i].vec[1][0];
391 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
392 *index=icu->bezt[i].vec[1][0];
402 /* Check constraint channels */
403 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
404 ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
405 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)) && conchan->ipo) {
406 for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
407 for (i=0; i<icu->totvert; i++){
408 if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] <= xmax ){
411 firstconchan=conchan;
412 firstvert=icu->bezt[i].vec[1][0];
413 *sel = icu->bezt[i].f2 & 1;
416 if (icu->bezt[i].f2 & 1){
419 foundx = icu->bezt[i].vec[1][0];
422 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
423 *index=icu->bezt[i].vec[1][0];
436 *rchan = firstconchan;
441 static IpoCurve *get_nearest_meshchannel_key (float *index, short *sel)
443 /* This function tries to find the RVK key that is
444 * closest to the user's mouse click
448 IpoCurve *firsticu=NULL;
450 float firstvert=-1, foundx=-1;
453 float ymin, ymax, ybase;
458 key = get_action_mesh_key();
460 /* lets get the mouse position and process it so
461 * we can start testing selections
463 getmouseco_areawin (mval);
465 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
467 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
469 ybase = key->totkey * (CHANNELHEIGHT + CHANNELSKIP);
470 ybase += CHANNELHEIGHT/2;
473 /* lets loop through the IpoCurves trying to find the closest
476 if (!key->ipo) return NULL;
477 for (icu = key->ipo->curve.first; icu ; icu = icu->next) {
478 /* lets not deal with the "speed" Ipo
480 if (!icu->adrcode) continue;
482 ymax = ybase - (CHANNELHEIGHT+CHANNELSKIP)*(icu->adrcode-1);
483 ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
485 /* Does this curve coorespond to the right
488 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
490 /* loop through the beziers in the curve
492 for (i=0; i<icu->totvert; i++){
494 /* Is this bezier in the right area?
496 if (icu->bezt[i].vec[1][0] > rectf.xmin &&
497 icu->bezt[i].vec[1][0] <= rectf.xmax ){
499 /* if no other curves have been picked ...
502 /* mark this curve/bezier as the first
506 firstvert=icu->bezt[i].vec[1][0];
508 /* sel = (is the bezier is already selected) ? 1 : 0;
510 *sel = icu->bezt[i].f2 & 1;
513 /* if the bezier is selected ...
515 if (icu->bezt[i].f2 & 1){
516 /* if we haven't found a selected one yet ...
519 /* record the found x value
522 foundx = icu->bezt[i].vec[1][0];
526 /* if the bezier is unselected and not at the x
527 * position of a previous found selected bezier ...
529 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
530 /* lets return this found curve/bezier
532 *index=icu->bezt[i].vec[1][0];
541 /* return what we've found
547 /* apparently within active object context */
548 static void mouse_action(int selectmode)
553 bActionChannel *chan;
554 bConstraintChannel *conchan;
557 act=G.saction->action;
561 getmouseco_areawin (mval);
563 chan=get_nearest_actionchannel_key(&selx, &sel, &conchan);
566 if (selectmode == SELECT_REPLACE) {
567 selectmode = SELECT_ADD;
569 deselect_actionchannel_keys(act, 0);
570 deselect_actionchannels(act, 0);
572 chan->flag |= ACHAN_SELECTED;
573 hilight_channel (act, chan, 1);
574 select_poseelement_by_name(chan->name, 1);
578 select_ipo_key(conchan->ipo, selx, selectmode);
580 select_ipo_key(chan->ipo, selx, selectmode);
583 std_rmouse_transform(transform_actionchannel_keys);
585 allqueue(REDRAWIPO, 0);
586 allqueue(REDRAWVIEW3D, 0);
587 allqueue(REDRAWACTION, 0);
588 allqueue(REDRAWNLA, 0);
593 static void mouse_mesh_action(int selectmode, Key *key)
595 /* Handle a right mouse click selection in an
596 * action window displaying RVK data
604 /* going to assume that the only reason
605 * we got here is because it has been
606 * determined that we are a mesh with
607 * the right properties (i.e., have key
611 /* get the click location, and the cooresponding
612 * ipo curve and selection time value
614 getmouseco_areawin (mval);
615 icu = get_nearest_meshchannel_key(&selx, &sel);
618 if (selectmode == SELECT_REPLACE) {
619 /* if we had planned to replace the
620 * selection, then we will first deselect
621 * all of the keys, and if the clicked on
622 * key had been unselected, we will select
623 * it, otherwise, we are done.
625 deselect_meshchannel_keys(key, 0);
628 selectmode = SELECT_ADD;
630 /* the key is selected so we should
631 * deselect -- but everything is now deselected
637 /* select the key using the given mode
638 * and redraw as mush stuff as needed.
640 select_icu_key(icu, selx, selectmode);
642 BIF_undo_push("Select Action key");
643 allqueue(REDRAWIPO, 0);
644 allqueue(REDRAWVIEW3D, 0);
645 allqueue(REDRAWACTION, 0);
646 allqueue(REDRAWNLA, 0);
651 void borderselect_action(void)
657 bActionChannel *chan;
658 bConstraintChannel *conchan;
662 act=G.saction->action;
668 if ( (val = get_border(&rect, 3)) ){
669 if (val == LEFTMOUSE)
670 selectmode = SELECT_ADD;
672 selectmode = SELECT_SUBTRACT;
675 mval[1]= rect.ymin+2;
676 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
678 mval[1]= rect.ymax-2;
679 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
681 ymax= count_action_levels(act) * (CHANNELHEIGHT+CHANNELSKIP);
682 ymax += CHANNELHEIGHT/2;
684 for (chan=act->chanbase.first; chan; chan=chan->next){
687 ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
688 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
689 borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax,
694 /* Check constraints */
695 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
696 ymin=ymax-(CHANNELHEIGHT+CHANNELSKIP);
697 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
698 borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax,
704 BIF_undo_push("Border Select Action");
705 allqueue(REDRAWNLA, 0);
706 allqueue(REDRAWACTION, 0);
707 allqueue(REDRAWIPO, 0);
711 void borderselect_mesh(Key *key)
714 int val, adrcodemax, adrcodemin;
717 int (*select_function)(BezTriple *);
720 if ( (val = get_border(&rect, 3)) ){
721 /* set the selection function based on what
722 * mouse button had been used in the border
725 if (val == LEFTMOUSE)
726 select_function = select_bezier_add;
728 select_function = select_bezier_subtract;
730 /* get the minimum and maximum adrcode numbers
731 * for the IpoCurves (this is the number that
732 * relates an IpoCurve to the keyblock it
736 mval[1]= rect.ymin+2;
737 adrcodemax = get_nearest_key_num(key, mval, &xmin);
738 adrcodemax = (adrcodemax >= key->totkey) ? key->totkey : adrcodemax;
741 mval[1]= rect.ymax-2;
742 adrcodemin = get_nearest_key_num(key, mval, &xmax);
743 adrcodemin = (adrcodemin < 1) ? 1 : adrcodemin;
745 /* Lets loop throug the IpoCurves and do borderselect
746 * on the curves with adrcodes in our selected range.
749 for (icu = key->ipo->curve.first; icu ; icu = icu->next) {
750 /* lets not deal with the "speed" Ipo
752 if (!icu->adrcode) continue;
753 if ( (icu->adrcode >= adrcodemin) &&
754 (icu->adrcode <= adrcodemax) ) {
755 borderselect_icu_key(icu, xmin, xmax, select_function);
760 BIF_undo_push("Border select Action Key");
761 allqueue(REDRAWNLA, 0);
762 allqueue(REDRAWACTION, 0);
763 allqueue(REDRAWIPO, 0);
767 /* ******************** action API ***************** */
769 /* generic get current action call, for action window context */
770 bAction *ob_get_action(Object *ob)
777 for (strip=ob->nlastrips.first; strip; strip=strip->next){
778 if (strip->flag & ACTSTRIP_SELECT)
784 /* used by ipo, outliner, buttons to find the active channel */
785 bActionChannel* get_hilighted_action_channel(bAction* action)
787 bActionChannel *chan;
792 for (chan=action->chanbase.first; chan; chan=chan->next){
793 if (chan->flag & ACHAN_SELECTED && chan->flag & ACHAN_HILIGHTED)
801 void set_exprap_action(int mode)
803 if(G.saction->action && G.saction->action->id.lib) return;
805 error ("Not yet implemented!");
808 bAction *add_empty_action(int blocktype)
815 else if(blocktype==ID_KE)
818 act= alloc_libblock(&G.main->action, ID_AC, str);
819 act->id.flag |= LIB_FAKEUSER;
824 void transform_actionchannel_keys(int mode, int dummy)
829 bConstraintChannel *conchan;
830 bActionChannel *chan;
831 float deltax, startx;
833 float sval[2], cval[2], lastcval[2];
837 int invert=0, firsttime=1;
840 short mvals[2], mvalc[2], cent[2];
843 act=G.saction->action;
845 /* Ensure that partial selections result in beztriple selections */
846 for (chan=act->chanbase.first; chan; chan=chan->next){
847 tvtot+=fullselect_ipo_keys(chan->ipo);
849 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
850 tvtot+=fullselect_ipo_keys(conchan->ipo);
853 /* If nothing is selected, bail out */
858 /* Build the transvert structure */
859 tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert");
861 for (chan=act->chanbase.first; chan; chan=chan->next){
862 /* Add the actionchannel */
863 tvtot = add_trans_ipo_keys(chan->ipo, tv, tvtot);
864 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
865 tvtot = add_trans_ipo_keys(conchan->ipo, tv, tvtot);
868 /* Do the event loop */
869 cent[0] = curarea->winx + (G.saction->v2d.hor.xmax)/2;
870 cent[1] = curarea->winy + (G.saction->v2d.hor.ymax)/2;
871 areamouseco_to_ipoco(G.v2d, cent, &cenf[0], &cenf[1]);
873 getmouseco_areawin (mvals);
874 areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]);
879 /* If we're cancelling, reset transformations */
880 /* Else calc new transformation */
881 /* Perform the transformations */
884 unsigned short event= extern_qread(&val);
901 arrows_move_cursor(event);
908 for (i=0; i<tvtot; i++) {
909 tv[i].loc[0]=tv[i].oldloc[0];
910 tv[i].loc[1]=tv[i].oldloc[1];
913 getmouseco_areawin (mvalc);
914 areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]);
916 if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
919 for (i=0; i<tvtot; i++){
920 tv[i].loc[0]=tv[i].oldloc[0];
924 deltax = cval[0]-sval[0];
927 apply_keyb_grid(&fac, 0.0, 1.0, 0.1, U.flag & USER_AUTOGRABGRID);
932 startx=mvals[0]-(ACTWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
933 deltax=mvalc[0]-(ACTWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
934 fac= fabs(deltax/startx);
936 apply_keyb_grid(&fac, 0.0, 0.2, 0.1, U.flag & USER_AUTOSIZEGRID);
940 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i+2].oldloc));
943 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i-2].oldloc));
948 startx= (G.scene->r.cfra);
950 tv[i].loc[0]-= startx;
952 tv[i].loc[0]+= startx;
960 sprintf(str, "sizeX: %.3f", fac);
964 sprintf(str, "deltaX: %.3f", fac);
968 if (G.saction->lock) {
970 ob->ctime= -1234567.0f;
971 if(ob->pose || ob_get_key(ob))
972 DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
974 DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
976 force_draw_plus(SPACE_VIEW3D, 0);
983 lastcval[0]= cval[0];
984 lastcval[1]= cval[1];
988 /* Update the curve */
989 /* Depending on the lock status, draw necessary views */
992 ob->ctime= -1234567.0f;
994 if(ob->pose || ob_get_key(ob))
995 DAG_object_flush_update(G.scene, ob, OB_RECALC_DATA);
997 DAG_object_flush_update(G.scene, ob, OB_RECALC_OB);
999 remake_action_ipos(act);
1001 if(cancel==0) BIF_undo_push("Transform Action");
1002 allqueue (REDRAWVIEW3D, 0);
1003 allqueue (REDRAWACTION, 0);
1004 allqueue(REDRAWNLA, 0);
1005 allqueue (REDRAWIPO, 0);
1009 void transform_meshchannel_keys(char mode, Key *key)
1011 /* this is the function that determines what happens
1012 * to those little blocky rvk key things you have selected
1013 * after you press a 'g' or an 's'. I'd love to say that
1014 * I have an intimate knowledge of all of what this function
1015 * is doing, but instead I'm just going to pretend.
1019 short mvals[2], mvalc[2], cent[2];
1020 float sval[2], cval[2], lastcval[2];
1025 float deltax, startx;
1027 int invert=0, firsttime=1;
1030 /* count all of the selected beziers, and
1031 * set all 3 control handles to selected
1033 tvtot=fullselect_ipo_keys(key->ipo);
1035 /* If nothing is selected, bail out
1041 /* Build the transvert structure
1043 tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert");
1046 tvtot = add_trans_ipo_keys(key->ipo, tv, tvtot);
1048 /* Do the event loop
1050 cent[0] = curarea->winx + (G.saction->v2d.hor.xmax)/2;
1051 cent[1] = curarea->winy + (G.saction->v2d.hor.ymax)/2;
1052 areamouseco_to_ipoco(G.v2d, cent, &cenf[0], &cenf[1]);
1054 getmouseco_areawin (mvals);
1055 areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]);
1060 * If we're cancelling, reset transformations
1061 * Else calc new transformation
1062 * Perform the transformations
1066 unsigned short event= extern_qread(&val);
1083 arrows_move_cursor(event);
1090 for (i=0; i<tvtot; i++) {
1091 tv[i].loc[0]=tv[i].oldloc[0];
1092 tv[i].loc[1]=tv[i].oldloc[1];
1096 getmouseco_areawin (mvalc);
1097 areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]);
1099 if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
1102 for (i=0; i<tvtot; i++){
1103 tv[i].loc[0]=tv[i].oldloc[0];
1107 deltax = cval[0]-sval[0];
1110 apply_keyb_grid(&fac, 0.0, 1.0, 0.1,
1111 U.flag & USER_AUTOGRABGRID);
1116 startx=mvals[0]-(ACTWIDTH/2+(curarea->winrct.xmax
1117 -curarea->winrct.xmin)/2);
1118 deltax=mvalc[0]-(ACTWIDTH/2+(curarea->winrct.xmax
1119 -curarea->winrct.xmin)/2);
1120 fac= fabs(deltax/startx);
1122 apply_keyb_grid(&fac, 0.0, 0.2, 0.1,
1123 U.flag & USER_AUTOSIZEGRID);
1127 memcpy (tv[i].loc, tv[i].oldloc,
1128 sizeof(tv[i+2].oldloc));
1131 memcpy (tv[i].loc, tv[i].oldloc,
1132 sizeof(tv[i-2].oldloc));
1137 startx= (G.scene->r.cfra);
1139 tv[i].loc[0]-= startx;
1141 tv[i].loc[0]+= startx;
1147 /* Display a message showing the magnitude of
1148 * the grab/scale we are performing
1151 sprintf(str, "sizeX: %.3f", fac);
1154 else if (mode=='g'){
1155 sprintf(str, "deltaX: %.3f", fac);
1159 if (G.saction->lock){
1160 /* doubt any of this code ever gets
1161 * executed, but it might in the
1165 DAG_object_flush_update(G.scene, OBACT, OB_RECALC_DATA);
1166 allqueue (REDRAWVIEW3D, 0);
1167 allqueue (REDRAWACTION, 0);
1168 allqueue (REDRAWIPO, 0);
1169 allqueue(REDRAWNLA, 0);
1173 addqueue (curarea->win, REDRAWALL, 0);
1178 lastcval[0]= cval[0];
1179 lastcval[1]= cval[1];
1183 /* fix up the Ipocurves and redraw stuff
1185 meshkey_do_redraw(key);
1186 BIF_undo_push("Transform Action Keys");
1190 /* did you understand all of that? I pretty much understand
1191 * what it does, but the specifics seem a little weird and crufty.
1195 void deselect_actionchannel_keys (bAction *act, int test)
1197 bActionChannel *chan;
1198 bConstraintChannel *conchan;
1204 /* Determine if this is selection or deselection */
1207 for (chan=act->chanbase.first; chan; chan=chan->next){
1208 /* Test the channel ipos */
1209 if (is_ipo_key_selected(chan->ipo)){
1214 /* Test the constraint ipos */
1215 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1216 if (is_ipo_key_selected(conchan->ipo)){
1230 for (chan=act->chanbase.first; chan; chan=chan->next){
1231 set_ipo_key_selection(chan->ipo, sel);
1232 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1233 set_ipo_key_selection(conchan->ipo, sel);
1237 void deselect_meshchannel_keys (Key *key, int test)
1239 /* should deselect the rvk keys
1243 /* Determine if this is selection or deselection */
1245 if (is_ipo_key_selected(key->ipo)){
1254 set_ipo_key_selection(key->ipo, sel);
1257 /* apparently within active object context */
1258 void deselect_actionchannels (bAction *act, int test)
1260 bActionChannel *chan;
1261 bConstraintChannel *conchan;
1267 /* See if we should be selecting or deselecting */
1269 for (chan=act->chanbase.first; chan; chan=chan->next){
1273 if (chan->flag & ACHAN_SELECTED){
1278 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1279 if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1290 /* Now set the flags */
1291 for (chan=act->chanbase.first; chan; chan=chan->next){
1292 select_poseelement_by_name(chan->name, sel);
1295 chan->flag |= ACHAN_SELECTED;
1297 chan->flag &= ~ACHAN_SELECTED;
1299 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1301 conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
1303 conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
1309 static void hilight_channel (bAction *act, bActionChannel *chan, short select)
1311 bActionChannel *curchan;
1316 for (curchan=act->chanbase.first; curchan; curchan=curchan->next){
1317 if (curchan==chan && select)
1318 curchan->flag |= ACHAN_HILIGHTED;
1320 curchan->flag &= ~ACHAN_HILIGHTED;
1324 /* select_mode = SELECT_REPLACE
1330 /* exported for outliner (ton) */
1331 /* apparently within active object context */
1332 int select_channel(bAction *act, bActionChannel *chan,
1335 /* Select the channel based on the selection mode
1339 switch (selectmode) {
1341 chan->flag |= ACHAN_SELECTED;
1343 case SELECT_SUBTRACT:
1344 chan->flag &= ~ACHAN_SELECTED;
1347 chan->flag ^= ACHAN_SELECTED;
1350 flag = (chan->flag & ACHAN_SELECTED) ? 1 : 0;
1352 hilight_channel(act, chan, flag);
1353 select_poseelement_by_name(chan->name, flag);
1358 static int select_constraint_channel(bAction *act,
1359 bConstraintChannel *conchan,
1361 /* Select the constraint channel based on the selection mode
1365 switch (selectmode) {
1367 conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
1369 case SELECT_SUBTRACT:
1370 conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
1373 conchan->flag ^= CONSTRAINT_CHANNEL_SELECT;
1376 flag = (conchan->flag & CONSTRAINT_CHANNEL_SELECT) ? 1 : 0;
1382 static void mouse_actionchannels(bAction *act, short *mval,
1383 short *mvalo, int selectmode) {
1384 /* Select action channels, based on mouse values.
1385 * If mvalo is NULL we assume it is a one click
1386 * action, other wise we treat it like it is a
1387 * border select with mval[0],mval[1] and
1388 * mvalo[0], mvalo[1] forming the corners of
1391 bActionChannel *chan;
1393 int clickmin, clickmax;
1395 bConstraintChannel *conchan;
1400 if (selectmode == SELECT_REPLACE) {
1401 deselect_actionchannels (act, 0);
1402 selectmode = SELECT_ADD;
1405 /* wsize is the greatest possible height (in pixels) that would be
1406 * needed to draw all of the action channels and constraint
1409 wsize = count_action_levels(act)*(CHANNELHEIGHT+CHANNELSKIP);
1410 wsize += CHANNELHEIGHT/2;
1412 areamouseco_to_ipoco(G.v2d, mval, &x, &y);
1413 clickmin = (int) ((wsize - y) / (CHANNELHEIGHT+CHANNELSKIP));
1415 /* Only one click */
1416 if (mvalo == NULL) {
1417 clickmax = clickmin;
1419 /* Two click values (i.e., border select */
1421 areamouseco_to_ipoco(G.v2d, mvalo, &x, &y);
1422 click = ((wsize - y) / (CHANNELHEIGHT+CHANNELSKIP));
1424 if ( ((int) click) < clickmin) {
1425 clickmax = clickmin;
1426 clickmin = (int) click;
1429 clickmax = (int) click;
1437 /* clickmin and clickmax now coorespond to indices into
1438 * the collection of channels and constraint channels.
1439 * What we need to do is apply the selection mode on all
1440 * channels and constraint channels between these indices.
1441 * This is done by traversing the channels and constraint
1442 * channels, for each item decrementing clickmin and clickmax.
1443 * When clickmin is less than zero we start selecting stuff,
1444 * until clickmax is less than zero or we run out of channels
1445 * and constraint channels.
1448 for (chan = act->chanbase.first; chan; chan=chan->next){
1449 if (clickmax < 0) break;
1451 if ( clickmin <= 0) {
1452 /* Select the channel with the given mode. If the
1453 * channel is freshly selected then set it to the
1454 * active channel for the action
1456 sel = (chan->flag & ACHAN_SELECTED);
1457 select_channel(act, chan, selectmode);
1462 /* Check for click in a constraint */
1463 for (conchan=chan->constraintChannels.first;
1464 conchan; conchan=conchan->next){
1465 if (clickmax < 0) break;
1466 if ( clickmin <= 0) {
1467 select_constraint_channel(act, conchan, selectmode);
1474 allqueue (REDRAWIPO, 0);
1475 allqueue (REDRAWVIEW3D, 0);
1476 allqueue (REDRAWACTION, 0);
1477 allqueue (REDRAWNLA, 0);
1480 void delete_meshchannel_keys(Key *key)
1482 if (!okee("Erase selected keys"))
1485 BIF_undo_push("Delete Action keys");
1486 delete_ipo_keys(key->ipo);
1488 meshkey_do_redraw(key);
1491 void delete_actionchannel_keys(void)
1494 bActionChannel *chan;
1495 bConstraintChannel *conchan;
1497 act = G.saction->action;
1501 if (!okee("Erase selected keys"))
1504 for (chan = act->chanbase.first; chan; chan=chan->next){
1506 /* Check action channel keys*/
1507 delete_ipo_keys(chan->ipo);
1509 /* Delete constraint channel keys */
1510 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1511 delete_ipo_keys(conchan->ipo);
1514 remake_action_ipos (act);
1515 BIF_undo_push("Delete Action keys");
1516 allspace(REMAKEIPO, 0);
1517 allqueue(REDRAWACTION, 0);
1518 allqueue(REDRAWIPO, 0);
1519 allqueue(REDRAWNLA, 0);
1522 static void delete_actionchannels (void)
1524 bConstraintChannel *conchan=NULL, *nextconchan;
1525 bActionChannel *chan, *next;
1529 act=G.saction->action;
1534 for (chan=act->chanbase.first; chan; chan=chan->next){
1535 if (chan->flag & ACHAN_SELECTED)
1537 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1539 if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1540 chan=act->chanbase.last;
1546 if (!chan && !conchan)
1549 if (!okee("Erase selected channels"))
1552 for (chan=act->chanbase.first; chan; chan=next){
1556 /* Remove action channels */
1557 if (chan->flag & ACHAN_SELECTED){
1559 chan->ipo->id.us--; /* Release the ipo */
1563 /* Remove constraint channels */
1564 for (conchan=chan->constraintChannels.first; conchan; conchan=nextconchan){
1565 nextconchan=conchan->next;
1566 if (freechan || conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1568 conchan->ipo->id.us--;
1569 BLI_freelinkN(&chan->constraintChannels, conchan);
1574 BLI_freelinkN (&act->chanbase, chan);
1578 BIF_undo_push("Delete Action channels");
1579 allqueue (REDRAWACTION, 0);
1580 allqueue(REDRAWNLA, 0);
1584 void sethandles_meshchannel_keys(int code, Key *key)
1586 sethandles_ipo_keys(key->ipo, code);
1588 BIF_undo_push("Set handles Action keys");
1589 meshkey_do_redraw(key);
1592 void sethandles_actionchannel_keys(int code)
1595 bActionChannel *chan;
1597 /* Get the selected action, exit if none are selected
1599 act = G.saction->action;
1603 /* Loop through the channels and set the beziers
1604 * of the selected keys based on the integer code
1606 for (chan = act->chanbase.first; chan; chan=chan->next){
1607 sethandles_ipo_keys(chan->ipo, code);
1610 /* Clean up and redraw stuff
1612 remake_action_ipos (act);
1613 BIF_undo_push("Set handles Action channel");
1614 allspace(REMAKEIPO, 0);
1615 allqueue(REDRAWACTION, 0);
1616 allqueue(REDRAWIPO, 0);
1617 allqueue(REDRAWNLA, 0);
1620 void set_ipotype_actionchannels(int ipotype) {
1623 bActionChannel *chan;
1626 /* Get the selected action, exit if none are selected
1628 act = G.saction->action;
1632 if (ipotype == SET_IPO_POPUP) {
1633 /* Present a popup menu asking the user what type
1634 * of IPO curve he/she/GreenBTH wants. ;)
1637 = pupmenu("Channel Ipo Type %t|"
1641 if(event < 1) return;
1645 /* Loop through the channels and for the selected ones set
1646 * the type for each Ipo curve in the channel Ipo (based on
1647 * the value from the popup).
1649 for (chan = act->chanbase.first; chan; chan=chan->next){
1650 if (chan->flag & ACHAN_SELECTED){
1652 setipotype_ipo(chan->ipo, ipotype);
1656 /* Clean up and redraw stuff
1658 remake_action_ipos (act);
1659 BIF_undo_push("Set Ipo type Action channel");
1660 allspace(REMAKEIPO, 0);
1661 allqueue(REDRAWACTION, 0);
1662 allqueue(REDRAWIPO, 0);
1663 allqueue(REDRAWNLA, 0);
1666 static void select_all_keys_frames(bAction *act, short *mval,
1667 short *mvalo, int selectmode) {
1669 /* This function tries to select all action keys in
1670 * every channel for a given range of keyframes that
1671 * are within the mouse values mval and mvalo (usually
1672 * the result of a border select). If mvalo is passed as
1673 * NULL then the selection is treated as a one-click and
1674 * the function tries to select all keys within half a
1675 * frame of the click point.
1680 bActionChannel *chan;
1681 bConstraintChannel *conchan;
1686 if (selectmode == SELECT_REPLACE) {
1687 deselect_actionchannel_keys(act, 0);
1688 selectmode = SELECT_ADD;
1691 if (mvalo == NULL) {
1692 rect.xmin = rect.xmax = mval[0];
1693 rect.ymin = rect.ymax = mval[1];
1696 if (mval[0] < mvalo[0] ) {
1697 rect.xmin = mval[0];
1698 rect.xmax = mvalo[0];
1701 rect.xmin = mvalo[0];
1702 rect.xmax = mval[0];
1704 if (mval[1] < mvalo[1] ) {
1705 rect.ymin = mval[1];
1706 rect.ymax = mvalo[1];
1709 rect.ymin = mvalo[1];
1710 rect.ymax = mval[1];
1715 mval[1]= rect.ymin+2;
1716 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1718 mval[1]= rect.ymax-2;
1719 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1721 if (mvalo == NULL) {
1722 rectf.xmin = rectf.xmin - 0.5;
1723 rectf.xmax = rectf.xmax + 0.5;
1726 for (chan=act->chanbase.first; chan; chan=chan->next){
1727 borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax,
1729 for (conchan=chan->constraintChannels.first; conchan;
1730 conchan=conchan->next){
1731 borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax,
1736 allqueue(REDRAWNLA, 0);
1737 allqueue(REDRAWACTION, 0);
1738 allqueue(REDRAWIPO, 0);
1742 static void select_all_keys_channels(bAction *act, short *mval,
1743 short *mvalo, int selectmode) {
1744 bActionChannel *chan;
1746 int clickmin, clickmax;
1748 bConstraintChannel *conchan;
1750 /* This function selects all the action keys that
1751 * are in the mouse selection range defined by
1752 * the ordered pairs mval and mvalo (usually
1753 * these 2 are obtained from a border select).
1754 * If mvalo is NULL, then the selection is
1755 * treated like a one-click action, and at most
1756 * one channel is selected.
1759 /* If the action is null then abort
1764 if (selectmode == SELECT_REPLACE) {
1765 deselect_actionchannel_keys(act, 0);
1766 selectmode = SELECT_ADD;
1769 /* wsize is the greatest possible height (in pixels) that would be
1770 * needed to draw all of the action channels and constraint
1774 wsize = count_action_levels(act)*(CHANNELHEIGHT+CHANNELSKIP);
1775 wsize += CHANNELHEIGHT/2;
1777 areamouseco_to_ipoco(G.v2d, mval, &x, &y);
1778 clickmin = (int) ((wsize - y) / (CHANNELHEIGHT+CHANNELSKIP));
1780 /* Only one click */
1781 if (mvalo == NULL) {
1782 clickmax = clickmin;
1784 /* Two click values (i.e., border select) */
1787 areamouseco_to_ipoco(G.v2d, mvalo, &x, &y);
1788 click = ((wsize - y) / (CHANNELHEIGHT+CHANNELSKIP));
1790 if ( ((int) click) < clickmin) {
1791 clickmax = clickmin;
1792 clickmin = (int) click;
1795 clickmax = (int) click;
1803 for (chan = act->chanbase.first; chan; chan=chan->next){
1804 if (clickmax < 0) break;
1806 if ( clickmin <= 0) {
1807 /* Select the channel with the given mode. If the
1808 * channel is freshly selected then set it to the
1809 * active channel for the action
1811 select_ipo_bezier_keys(chan->ipo, selectmode);
1816 /* Check for click in a constraint */
1817 for (conchan=chan->constraintChannels.first;
1818 conchan; conchan=conchan->next){
1819 if (clickmax < 0) break;
1820 if ( clickmin <= 0) {
1821 select_ipo_bezier_keys(chan->ipo, selectmode);
1828 allqueue (REDRAWIPO, 0);
1829 allqueue (REDRAWVIEW3D, 0);
1830 allqueue (REDRAWACTION, 0);
1831 allqueue (REDRAWNLA, 0);
1835 static void borderselect_function(void (*select_func)(bAction *act,
1839 /* This function executes an arbitrary selection
1840 * function as part of a border select. This
1841 * way the same function that is used for
1842 * right click selection points can generally
1843 * be used as the argument to this function
1846 short mval[2], mvalo[2];
1850 /* Get the selected action, exit if none are selected
1852 act=G.saction->action;
1856 /* Let the user draw a border (or abort)
1858 if ( (val=get_border (&rect, 3)) ) {
1860 mval[1]= rect.ymin+2;
1861 mvalo[0]= rect.xmax;
1862 mvalo[1]= rect.ymax-2;
1864 /* if the left mouse was used, do an additive
1865 * selection with the user defined selection
1868 if (val == LEFTMOUSE)
1869 select_func(act, mval, mvalo, SELECT_ADD);
1871 /* if the right mouse was used, do a subtractive
1872 * selection with the user defined selection
1875 else if (val == RIGHTMOUSE)
1876 select_func(act, mval, mvalo, SELECT_SUBTRACT);
1878 BIF_undo_push("Border select Action");
1882 static void clever_keyblock_names(Key *key, short* mval){
1883 int but=0, i, keynum;
1887 /* get the keynum cooresponding to the y value
1888 * of the mouse pointer, return if this is
1889 * an invalid key number (and we don't deal
1890 * with the speed ipo).
1893 keynum = get_nearest_key_num(key, mval, &x);
1894 if ( (keynum < 1) || (keynum >= key->totkey) )
1897 kb= key->block.first;
1898 for (i=0; i<keynum; ++i) kb = kb->next;
1900 if (kb->name[0] == '\0') {
1901 sprintf(str, "Key %d", keynum);
1904 strcpy(str, kb->name);
1907 if ( (kb->slidermin >= kb->slidermax) ) {
1908 kb->slidermin = 0.0;
1909 kb->slidermax = 1.0;
1912 add_numbut(but++, TEX, "KB: ", 0, 24, str,
1913 "Does this really need a tool tip?");
1914 add_numbut(but++, NUM|FLO, "Slider Min:",
1915 -10000, kb->slidermax, &kb->slidermin, 0);
1916 add_numbut(but++, NUM|FLO, "Slider Max:",
1917 kb->slidermin, 10000, &kb->slidermax, 0);
1919 if (do_clever_numbuts(str, but, REDRAW)) {
1920 strcpy(kb->name, str);
1921 allqueue (REDRAWACTION, 0);
1922 allspace(REMAKEIPO, 0);
1923 allqueue (REDRAWIPO, 0);
1929 static void numbuts_action(void)
1931 /* now called from action window event loop, plus reacts on mouseclick */
1932 /* removed Hos grunts for that reason! :) (ton) */
1936 if ( (key = get_action_mesh_key()) ) {
1937 getmouseco_areawin (mval);
1938 if (mval[0]<NAMEWIDTH) {
1939 clever_keyblock_names(key, mval);
1944 void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
1946 extern void do_actionbuts(unsigned short event); // drawaction.c
1947 SpaceAction *saction;
1954 unsigned short event= evt->event;
1955 short val= evt->val;
1956 short mousebut = L_MOUSE;
1958 if(curarea->win==0) return;
1960 saction= curarea->spacedata.first;
1964 act=saction->action;
1967 if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
1969 /* swap mouse buttons based on user preference */
1970 if (U.flag & USER_LMOUSESELECT) {
1971 if (event == LEFTMOUSE) {
1974 } else if (event == RIGHTMOUSE) {
1980 getmouseco_areawin(mval);
1982 key = get_action_mesh_key();
1986 do_actionbuts(val); // window itself
1990 do_action_buttons(B_ACTHOME); // header
1995 if (mval[0]<ACTWIDTH){
1999 deselect_meshchannel_keys(key, 1);
2000 allqueue (REDRAWACTION, 0);
2001 allqueue(REDRAWNLA, 0);
2002 allqueue (REDRAWIPO, 0);
2006 if (mval[0]<NAMEWIDTH){
2007 deselect_actionchannels (act, 1);
2008 allqueue (REDRAWVIEW3D, 0);
2009 allqueue (REDRAWACTION, 0);
2010 allqueue(REDRAWNLA, 0);
2011 allqueue (REDRAWIPO, 0);
2013 else if (mval[0]>ACTWIDTH){
2014 deselect_actionchannel_keys (act, 1);
2015 allqueue (REDRAWACTION, 0);
2016 allqueue(REDRAWNLA, 0);
2017 allqueue (REDRAWIPO, 0);
2024 if (mval[0]<ACTWIDTH){
2028 borderselect_mesh(key);
2033 /* If the border select is initiated in the
2034 * part of the action window where the channel
2035 * names reside, then select the channels
2037 if (mval[0]<NAMEWIDTH){
2038 borderselect_function(mouse_actionchannels);
2039 BIF_undo_push("Select Action");
2041 else if (mval[0]>ACTWIDTH){
2043 /* If the border select is initiated in the
2044 * vertical scrollbar, then (de)select all keys
2045 * for the channels in the selection region
2047 if (IN_2D_VERT_SCROLL(mval)) {
2048 borderselect_function(select_all_keys_channels);
2051 /* If the border select is initiated in the
2052 * horizontal scrollbar, then (de)select all keys
2053 * for the keyframes in the selection region
2055 else if (IN_2D_HORIZ_SCROLL(mval)) {
2056 borderselect_function(select_all_keys_frames);
2059 /* Other wise, select the action keys
2062 borderselect_action();
2069 /* scroll the window so the current
2070 * frame is in the center.
2077 if (G.qual & LR_SHIFTKEY && mval[0]>ACTWIDTH) {
2078 duplicate_meshchannel_keys(key);
2082 if (G.qual & LR_SHIFTKEY && mval[0]>ACTWIDTH){
2083 duplicate_actionchannel_keys();
2084 remake_action_ipos(act);
2090 if (mval[0]>=ACTWIDTH) {
2092 transform_meshchannel_keys('g', key);
2095 transform_actionchannel_keys ('g', 0);
2102 if(G.qual & LR_SHIFTKEY) {
2103 sethandles_meshchannel_keys(HD_AUTO, key);
2106 sethandles_meshchannel_keys(HD_ALIGN, key);
2110 if(G.qual & LR_SHIFTKEY) {
2111 sethandles_actionchannel_keys(HD_AUTO);
2114 sethandles_actionchannel_keys(HD_ALIGN);
2123 /* no panel (yet). current numbuts are not easy to put in panel... */
2124 //add_blockhandler(curarea, ACTION_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);
2125 //scrarea_queue_winredraw(curarea);
2130 if (mval[0]>=ACTWIDTH) {
2132 transform_meshchannel_keys('s', key);
2135 transform_actionchannel_keys ('s', 0);
2140 /*** set the Ipo type ***/
2146 set_ipotype_actionchannels(SET_IPO_POPUP);
2152 sethandles_meshchannel_keys(HD_VECT, key);
2156 sethandles_actionchannel_keys(HD_VECT);
2165 if(G.qual & LR_SHIFTKEY) {
2180 if(G.qual & LR_SHIFTKEY) {
2181 bottom_sel_action();
2191 delete_meshchannel_keys(key);
2194 if (mval[0]<NAMEWIDTH)
2195 delete_actionchannels ();
2197 delete_actionchannel_keys ();
2200 /* LEFTMOUSE and RIGHTMOUSE event codes can be swapped above,
2201 * based on user preference USER_LMOUSESELECT
2204 if(view2dmove(LEFTMOUSE)) // only checks for sliders
2206 else if (mval[0]>ACTWIDTH){
2208 getmouseco_areawin(mval);
2210 areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
2213 if(cfra< 1) cfra= 1;
2217 update_for_newframe();
2218 force_draw_all(0); }
2219 else PIL_sleep_ms(30);
2221 } while(get_mbut() & mousebut);
2224 /* passed on as selection */
2226 /* Clicking in the channel area selects the
2227 * channel or constraint channel
2229 if (mval[0]<NAMEWIDTH) {
2231 if(G.qual & LR_SHIFTKEY)
2232 mouse_actionchannels(act, mval, NULL, SELECT_INVERT);
2234 mouse_actionchannels(act, mval, NULL, SELECT_REPLACE);
2236 BIF_undo_push("Select Action");
2238 else numbuts_action();
2240 else if (mval[0]>ACTWIDTH) {
2242 /* Clicking in the vertical scrollbar selects
2243 * all of the keys for that channel at that height
2245 if (IN_2D_VERT_SCROLL(mval)) {
2246 if(G.qual & LR_SHIFTKEY)
2247 select_all_keys_channels(act, mval, NULL,
2250 select_all_keys_channels(act, mval, NULL,
2254 /* Clicking in the horizontal scrollbar selects
2255 * all of the keys within 0.5 of the nearest integer
2258 else if (IN_2D_HORIZ_SCROLL(mval)) {
2259 if(G.qual & LR_SHIFTKEY)
2260 select_all_keys_frames(act, mval, NULL,
2263 select_all_keys_frames(act, mval, NULL,
2265 BIF_undo_push("Select all Action");
2268 /* Clicking in the main area of the action window
2273 if(G.qual & LR_SHIFTKEY)
2274 mouse_mesh_action(SELECT_INVERT, key);
2276 mouse_mesh_action(SELECT_REPLACE, key);
2279 if(G.qual & LR_SHIFTKEY)
2280 mouse_action(SELECT_INVERT);
2282 mouse_action(SELECT_REPLACE);
2288 view2d_zoom(G.v2d, 0.1154, sa->winx, sa->winy);
2289 test_view2d(G.v2d, sa->winx, sa->winy);
2293 view2d_zoom(G.v2d, -0.15, sa->winx, sa->winy);
2294 test_view2d(G.v2d, sa->winx, sa->winy);
2299 case WHEELDOWNMOUSE:
2300 view2dmove(event); /* in drawipo.c */
2305 if(doredraw) addqueue(curarea->win, REDRAW, 1);
2309 Key *get_action_mesh_key(void)
2311 /* gets the key data from the currently selected
2312 * mesh/lattice. If a mesh is not selected, or does not have
2313 * key data, then we return NULL (currently only
2314 * returns key data for RVK type meshes). If there
2315 * is an action that is pinned, return null
2321 if (!ob) return NULL;
2323 if (G.saction->pin) return NULL;
2325 if (ob->type==OB_MESH ) {
2326 key = ((Mesh *)ob->data)->key;
2328 else if (ob->type==OB_LATTICE ) {
2329 key = ((Lattice *)ob->data)->key;
2334 if (key->type == KEY_RELATIVE)
2341 int get_nearest_key_num(Key *key, short *mval, float *x) {
2342 /* returns the key num that cooresponds to the
2343 * y value of the mouse click. Does not check
2344 * if this is a valid keynum. Also gives the Ipo
2350 areamouseco_to_ipoco(G.v2d, mval, x, &y);
2352 ybase = key->totkey * (CHANNELHEIGHT + CHANNELSKIP);
2353 num = (int) ((ybase - y + CHANNELHEIGHT/2) / (CHANNELHEIGHT+CHANNELSKIP));
2360 void top_sel_action()
2363 bActionChannel *chan;
2365 /* Get the selected action, exit if none are selected */
2366 act = G.saction->action;
2369 for (chan=act->chanbase.first; chan; chan=chan->next){
2370 if ((chan->flag & ACHAN_SELECTED) && !(chan->flag & ACHAN_MOVED)){
2371 /* take it out off the chain keep data */
2372 BLI_remlink (&act->chanbase, chan);
2373 /* make it first element */
2374 BLI_insertlinkbefore(&act->chanbase,act->chanbase.first, chan);
2375 chan->flag |= ACHAN_MOVED;
2376 /* restart with rest of list */
2380 /* clear temp flags */
2381 for (chan=act->chanbase.first; chan; chan=chan->next){
2382 chan->flag = chan->flag & ~ACHAN_MOVED;
2385 /* Clean up and redraw stuff */
2386 remake_action_ipos (act);
2387 BIF_undo_push("Top Action channel");
2388 allspace(REMAKEIPO, 0);
2389 allqueue(REDRAWACTION, 0);
2390 allqueue(REDRAWIPO, 0);
2391 allqueue(REDRAWNLA, 0);
2394 void up_sel_action()
2397 bActionChannel *chan;
2398 bActionChannel *prev;
2400 /* Get the selected action, exit if none are selected */
2401 act = G.saction->action;
2404 for (chan=act->chanbase.first; chan; chan=chan->next){
2405 if ((chan->flag & ACHAN_SELECTED) && !(chan->flag & ACHAN_MOVED)){
2408 /* take it out off the chain keep data */
2409 BLI_remlink (&act->chanbase, chan);
2411 BLI_insertlinkbefore(&act->chanbase,prev, chan);
2412 chan->flag |= ACHAN_MOVED;
2413 /* restart with rest of list */
2418 /* clear temp flags */
2419 for (chan=act->chanbase.first; chan; chan=chan->next){
2420 chan->flag = chan->flag & ~ACHAN_MOVED;
2423 /* Clean up and redraw stuff
2425 remake_action_ipos (act);
2426 BIF_undo_push("Up Action channel");
2427 allspace(REMAKEIPO, 0);
2428 allqueue(REDRAWACTION, 0);
2429 allqueue(REDRAWIPO, 0);
2430 allqueue(REDRAWNLA, 0);
2433 void down_sel_action()
2436 bActionChannel *chan;
2437 bActionChannel *next;
2439 /* Get the selected action, exit if none are selected */
2440 act = G.saction->action;
2443 for (chan=act->chanbase.last; chan; chan=chan->prev){
2444 if ((chan->flag & ACHAN_SELECTED) && !(chan->flag & ACHAN_MOVED)){
2446 if (next) next = next->next;
2448 /* take it out off the chain keep data */
2449 BLI_remlink (&act->chanbase, chan);
2451 BLI_insertlinkbefore(&act->chanbase,next, chan);
2452 chan->flag |= ACHAN_MOVED;
2455 /* take it out off the chain keep data */
2456 BLI_remlink (&act->chanbase, chan);
2458 BLI_addtail(&act->chanbase,chan);
2459 chan->flag |= ACHAN_MOVED;
2464 /* clear temp flags */
2465 for (chan=act->chanbase.first; chan; chan=chan->next){
2466 chan->flag = chan->flag & ~ACHAN_MOVED;
2469 /* Clean up and redraw stuff
2471 remake_action_ipos (act);
2472 BIF_undo_push("Down Action channel");
2473 allspace(REMAKEIPO, 0);
2474 allqueue(REDRAWACTION, 0);
2475 allqueue(REDRAWIPO, 0);
2476 allqueue(REDRAWNLA, 0);
2479 void bottom_sel_action()
2482 bActionChannel *chan;
2484 /* Get the selected action, exit if none are selected */
2485 act = G.saction->action;
2488 for (chan=act->chanbase.last; chan; chan=chan->prev){
2489 if ((chan->flag & ACHAN_SELECTED) && !(chan->flag & ACHAN_MOVED)) {
2490 /* take it out off the chain keep data */
2491 BLI_remlink (&act->chanbase, chan);
2493 BLI_addtail(&act->chanbase,chan);
2494 chan->flag |= ACHAN_MOVED;
2498 /* clear temp flags */
2499 for (chan=act->chanbase.first; chan; chan=chan->next){
2500 chan->flag = chan->flag & ~ACHAN_MOVED;
2503 /* Clean up and redraw stuff
2505 remake_action_ipos (act);
2506 BIF_undo_push("Bottom Action channel");
2507 allspace(REMAKEIPO, 0);
2508 allqueue(REDRAWACTION, 0);
2509 allqueue(REDRAWIPO, 0);
2510 allqueue(REDRAWNLA, 0);