66311538ac4bca1ef21b0a0a17fdf579ff8fe00b
[blender.git] / source / blender / src / editnla.c
1 /**
2 * $Id$
3 *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
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
12  * about this.
13  *
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.
18  *
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.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31 * This file is a horrible mess: An attmept to cram some
32 * final functionality into blender before it is too late.
33 *
34 * Hopefully it can be tidied up at a later date...
35 */
36
37 #include <stdlib.h>
38 #include <string.h>
39 #include <math.h>
40
41 #include "PIL_time.h"
42
43 #include "BKE_global.h"
44 #include "BKE_main.h"
45 #include "BKE_library.h"
46 #include "BKE_nla.h"
47 #include "BKE_action.h"
48
49 #include "BIF_screen.h"
50 #include "BIF_interface.h"
51 #include "BIF_buttons.h"
52 #include "BIF_space.h"
53 #include "BIF_mywindow.h"
54 #include "BIF_editview.h"
55 #include "BIF_toolbox.h"
56
57 #include "MEM_guardedalloc.h"
58
59 #include "BLI_blenlib.h"
60
61 #include "DNA_screen_types.h"
62 #include "DNA_space_types.h"
63 #include "DNA_scene_types.h"
64 #include "DNA_ipo_types.h"
65 #include "DNA_curve_types.h"
66 #include "DNA_object_types.h"
67 #include "DNA_userdef_types.h"
68 #include "DNA_action_types.h"
69 #include "DNA_nla_types.h"
70 #include "DNA_constraint_types.h"
71
72 #include "BSE_editipo.h"
73 #include "BSE_editnla_types.h"
74 #include "BSE_headerbuttons.h"
75 #include "BSE_drawipo.h"
76 #include "BSE_trans_types.h"
77 #include "BSE_edit.h"
78 #include "BDR_editobject.h"
79
80 #include "interface.h"
81 #include "blendef.h"
82 #include "mydevice.h"
83 #include "blendertimer.h"
84
85 #ifdef HAVE_CONFIG_H
86 #include <config.h>
87 #endif
88
89 /* Note: A lot of these pretty much duplicate the behaviour of the
90 action windows.  The functions should be shared, not copy-pasted */
91 typedef struct NlaParam{
92         SpaceNla *snla;
93         unsigned short event;
94         short val;
95 }NlaParam;
96
97 static void deselect_nlachannel_keys (int test);
98 static void deselect_nlachannels(int test);
99 static void transform_nlachannel_keys(char mode);       
100 static void delete_nlachannel_keys(void);
101 static void delete_nlachannels(void);
102 static void duplicate_nlachannel_keys(void);
103 static void borderselect_nla(void);
104 static void mouse_nla(void);
105 static Base *get_nearest_nlachannel_ob_key (float *index, short *sel);
106 static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel);
107 static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel);
108
109 static void mouse_nlachannels(short mval[2]);
110 static void add_nlablock(short mval[2]);
111 static bActionStrip *get_active_nlastrip(void);
112 static void convert_nla(short mval[2]);
113
114 extern int count_nla_levels(void);      /* From drawnla.c */
115 extern int nla_filter (Base* base, int flags);  /* From drawnla.c */
116
117 /* ******************** SPACE: NLA ********************** */
118
119 /* Protected creator function */
120 int calc_memleak (void* ptr){
121         int doredraw= 0;
122         short   mval[2];
123         float dx,dy;
124         int     cfra;
125         SpaceNla *snla;
126         NlaParam *params=(NlaParam*) ptr;
127         unsigned short event;
128         short val ;
129
130         if (!ptr)
131                 return -1;
132
133         snla= params->snla;
134         event = params->event;
135         val = params->val;
136         
137         if(curarea->win==0) return 0;
138         
139         if (!snla)
140                 return 0;
141         
142         if(val) {
143                 if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
144                 
145                 getmouseco_areawin(mval);
146                 
147                 switch(event) {
148                 case UI_BUT_EVENT:
149                         do_blenderbuttons(val);
150                         break;
151                 case HOMEKEY:
152                         do_nla_buttons(B_NLAHOME);
153                         break;
154                 case DKEY:
155                         if (G.qual & LR_SHIFTKEY && mval[0]>=NLAWIDTH){
156                                 duplicate_nlachannel_keys();
157                                 update_for_newframe();
158                         }
159                         break;
160                 case DELKEY:
161                 case XKEY:
162                         if (mval[0]>=NLAWIDTH)
163                                 delete_nlachannel_keys ();
164                         else
165                                 delete_nlachannels();
166                         update_for_newframe();
167                         break;
168                 case GKEY:
169                         if (mval[0]>=NLAWIDTH)
170                                 transform_nlachannel_keys ('g');
171                         update_for_newframe();
172                         break;
173                 case SKEY:
174                         if (mval[0]>=NLAWIDTH)
175                                 transform_nlachannel_keys ('s');
176                         update_for_newframe();
177                         break;
178                 case BKEY:
179                         borderselect_nla();
180                         break;
181                 case CKEY:
182                         convert_nla(mval);
183                         break;
184                         
185                 case AKEY:
186                         if (G.qual & LR_SHIFTKEY){
187                                 add_nlablock(mval);
188                                 allqueue (REDRAWNLA, 0);
189                                 allqueue (REDRAWVIEW3D, 0);
190                         }
191                         else{
192                                 if (mval[0]>=NLAWIDTH)
193                                         deselect_nlachannel_keys(1);
194                                 else{
195                                         deselect_nlachannels(1);
196                                         allqueue (REDRAWVIEW3D, 0);
197                                 }
198                                 allqueue (REDRAWNLA, 0);
199                                 allqueue (REDRAWIPO, 0);
200                         }
201                         break;
202                 case RIGHTMOUSE:
203                         if (mval[0]>=NLAWIDTH)
204                                 mouse_nla();
205                         else
206                                 mouse_nlachannels(mval);
207                         break;
208                 case LEFTMOUSE:
209                         if (mval[0]>NLAWIDTH){
210                                 do {
211                                         getmouseco_areawin(mval);
212                                         
213                                         areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
214                                         
215                                         cfra= (int)dx;
216                                         if(cfra< 1) cfra= 1;
217                                         
218                                         if( cfra!=CFRA ) {
219                                                 CFRA= cfra;
220                                                 update_for_newframe();
221                                                 force_draw_plus(SPACE_VIEW3D);
222                                                 force_draw_plus(SPACE_IPO);
223                                         }
224                                         
225                                 } while(get_mbut()&L_MOUSE);
226                         }
227                         
228                         break;
229                 case MIDDLEMOUSE:
230                 case WHEELUPMOUSE:
231                 case WHEELDOWNMOUSE:
232                         view2dmove(event);      /* in drawipo.c */
233                         break;
234                 }
235         }
236         
237         if(doredraw) scrarea_queue_winredraw(curarea);
238         return 0;
239 }
240
241 void winqreadnlaspace(unsigned short event, short val, char ascii)
242 {
243         NlaParam param;
244         Base *base;
245         bActionStrip *strip, *next;
246         short mval[2];
247         float dx, dy;
248         int cfra;
249
250         param.event = event;
251         param.val = val;
252         param.snla = curarea->spacedata.first;
253
254
255         /* Call the protected (&obfuscated) eventloop function */
256         calc_memleak(&param); /* enable NLA */
257 }
258
259 static void convert_nla(short mval[2])
260 {
261         short event;
262         float   ymax, ymin;
263         Base *base;
264         float x,y;
265         int sel=0;
266         bActionStrip *strip, *nstrip;
267         /* Find out what strip we're over */
268         ymax = count_nla_levels() * (NLACHANNELSKIP+NLACHANNELHEIGHT);
269         areamouseco_to_ipoco(G.v2d, mval, &x, &y);
270         
271         for (base=G.scene->base.first; base; base=base->next){
272                 if (nla_filter(base, 0)){
273                         /* Check object ipo */
274                         ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
275                         if (y>=ymin && y<=ymax)
276                                 break;
277                         ymax=ymin;
278                         
279                         if (base->object->type==OB_ARMATURE){
280                                 /* Check action ipo */
281                                 ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
282                                 if (y>=ymin && y<=ymax)
283                                         break;
284                                 ymax=ymin;
285                                 
286                                 /* Check nlastrips */
287                                 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
288                                         ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
289                                         if (y>=ymin && y<=ymax){
290                                                 sel = 1;
291                                                 break;
292                                         }
293                                         ymax=ymin;
294                                 }
295                                 if (sel)
296                                         break;
297                         }
298                 }
299         }
300         
301         if (!base)
302                 return;
303         
304         if (base->object->type==OB_ARMATURE){
305                 event = pupmenu("Convert%t|Action to NLAstrip%x1");
306                 switch (event){
307                 case 1:
308                         if (base->object->action){
309                                 /* Make new actionstrip */
310                                 nstrip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
311                                 
312                                 deselect_nlachannel_keys(0);
313                                 
314                                 /* Link the action to the nstrip */
315                                 nstrip->act = base->object->action;
316                                 nstrip->actstart = calc_action_start(base->object->action);     /* MAKE THIS THE FIRST FRAME OF THE ACTION */
317                                 nstrip->actend = calc_action_end(base->object->action);
318                                 nstrip->start = nstrip->actstart;
319                                 nstrip->end = nstrip->actend;
320                                 nstrip->flag = ACTSTRIP_SELECT;
321                                 nstrip->repeat = 1.0;
322                                                                 
323                                 BLI_addtail(&base->object->nlastrips, nstrip);
324                                 
325                                 /* Unlink action */
326                                 base->object->action = NULL;
327                                 
328                                 allqueue (REDRAWNLA, 0);
329                         }
330                         
331                         
332                         break;
333                 default:
334                         break;
335                 }
336         }
337 }
338
339 static void add_nlablock(short mval[2])
340 {
341         /* Make sure we are over an armature */
342         Base *base;
343         bAction *act=NULL;
344         bActionStrip *strip;
345         float ymin, ymax;
346         float x, y;
347         rctf    rectf;
348         short event;
349         char *str;
350         short nr;
351         int             cur;
352         
353         areamouseco_to_ipoco(G.v2d, mval, &x, &y);
354         
355         mval[0]-=7;
356         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
357         
358         mval[0]+=14;
359         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
360         
361         ymax = count_nla_levels();      
362         ymax*=(NLACHANNELHEIGHT + NLACHANNELSKIP);
363         
364         for (base=G.scene->base.first; base; base=base->next){
365                 /* Handle object ipo selection */
366                 if (nla_filter(base, 0)){
367                         
368                         /* STUPID STUPID STUPID */
369                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
370                         
371                         /* Handle object ipos */
372                         if (base->object->type==OB_ARMATURE){
373                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
374                                         break;          
375                         }
376                         
377                         ymax=ymin;
378                         
379                         /* Handle action ipos & Action strips */
380                         if (base->object->type==OB_ARMATURE){
381                                 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP)*(BLI_countlist(&base->object->nlastrips) + 1);
382                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
383                                         break;
384                                 ymax=ymin;
385                                 
386                                 
387                         }                       
388                 }
389         }       
390         
391         /* Make sure we have an armature */
392         if (!base){
393                 error ("Not an armature!");
394                 return;
395         }
396         
397         /* Popup action menu */
398         IDnames_to_pupstring(&str, "Add action", NULL, &G.main->action, (ID *)G.scene, &nr);
399
400         event = pupmenu(str);
401         
402         if (event!=-1){
403                 for (cur = 1, act=G.main->action.first; act; act=act->id.next, cur++){
404                         if (cur==event){
405                                 break;
406                         }
407                 }
408         }
409         
410         MEM_freeN(str);
411         
412         /* Bail out if no action was chosen */
413         if (!act){
414                 return;
415         }
416         
417         /* Initialize the new action block */
418         strip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
419         
420         deselect_nlachannel_keys(0);
421         
422         /* Link the action to the strip */
423         strip->act = act;
424         strip->actstart = 1.0;
425         strip->actend = calc_action_end(act);
426         strip->start = G.scene->r.cfra; /* Should be mval[0] */
427         strip->end = strip->start + (strip->actend-strip->actstart);
428         strip->flag = ACTSTRIP_SELECT;
429         strip->repeat = 1.0;
430         
431         act->id.us++;
432         
433         BLI_addtail(&base->object->nlastrips, strip);
434 }
435
436 static void mouse_nlachannels(short mval[2])
437 {
438         /* Find which strip has been clicked */
439 //      bActionChannel *chan;
440         bConstraintChannel *conchan=NULL;
441         bActionStrip *strip;
442         float   click;
443         int             wsize;
444         int             sel;
445         Base    *base;
446         
447         wsize = (count_nla_levels ()*(NLACHANNELHEIGHT+NLACHANNELSKIP));
448
449
450         click = (wsize-(mval[1]+G.v2d->cur.ymin));
451         click += NLACHANNELHEIGHT/2;
452         click /= (NLACHANNELHEIGHT+NLACHANNELSKIP);
453
454         if (click<0)
455                 return;
456
457         for (base = G.scene->base.first; base; base=base->next){
458                 if (nla_filter(base, 0)){
459                         /* See if this is a base selected */
460                         if ((int)click==0)
461                                 break;
462                         
463                         click--;
464                         
465                         /* Check for click in a constraint */
466                         for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
467                                 if ((int)click==0){
468                                         base=G.scene->base.last;
469                                         break;
470                                 }
471                                 click--;
472                         }
473
474                         /* See if this is an action */
475                         if (base->object->type==OB_ARMATURE && base->object->action){
476                                 if ((int)click==0){
477                                         break;
478                                 }
479                                 click--;
480                         }
481
482                         /* See if this is an nla strip */
483                         for (strip = base->object->nlastrips.first; strip; strip=strip->next){
484                                 if ((int)click==0){
485                                         base=G.scene->base.last;
486                                         break;
487                                 }
488                                 click--;                                
489                         }
490                 }
491         }
492
493         if (!base && !conchan)
494                 return;
495
496         /* Handle constraint strip selection */
497         if (conchan){
498                 if (conchan->flag & CONSTRAINT_CHANNEL_SELECT)
499                         sel = 0;
500                 else
501                         sel =1;
502                 
503                 /* Channel names clicking */
504                 if (G.qual & LR_SHIFTKEY){
505                         //              select_poseelement_by_name(chan->name, !(chan->flag & ACHAN_SELECTED));
506                         if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
507                                 conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
508                                 //      hilight_channel(act, chan, 0);
509                         }
510                         else{
511                                 conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
512                                 //      hilight_channel(act, chan, 1);
513                         }
514                 }
515                 else{
516                         deselect_nlachannels (0);       // Auto clear
517                         conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
518                         //      hilight_channel(act, chan, 1);
519                         //      act->achan = chan;
520                         //      select_poseelement_by_name(chan->name, 1);
521                 }
522                 
523         }
524         
525         /* Handle object strip selection */
526         else if (base)
527         {
528                 /* Choose the mode */
529                 if (base->flag & SELECT)
530                         sel = 0;
531                 else
532                         sel =1;
533                 
534                 /* Channel names clicking */
535                 if (G.qual & LR_SHIFTKEY){
536         //              select_poseelement_by_name(chan->name, !(chan->flag & ACHAN_SELECTED));
537                         if (base->flag & SELECT){
538                                 base->flag &= ~SELECT;
539                 //              hilight_channel(act, chan, 0);
540                         }
541                         else{
542                                 base->flag |= SELECT;
543                 //              hilight_channel(act, chan, 1);
544                         }
545                 }
546                 else{
547                         deselect_nlachannels (0);       // Auto clear
548                         base->flag |= SELECT;
549                 //      hilight_channel(act, chan, 1);
550                 //      act->achan = chan;
551                 //      select_poseelement_by_name(chan->name, 1);
552                 }
553                 
554         }
555         allqueue (REDRAWIPO, 0);
556         allqueue (REDRAWVIEW3D, 0);
557         allqueue (REDRAWACTION, 0);
558         allqueue(REDRAWNLA, 0);
559         
560 }
561
562 void init_nlaspace(ScrArea *sa)
563 {
564         SpaceNla *snla;
565         
566         snla= MEM_callocN(sizeof(SpaceNla), "initnlaspace");
567         BLI_addhead(&sa->spacedata, snla);
568         
569         snla->spacetype= SPACE_NLA;
570         
571         snla->v2d.tot.xmin= 1.0;
572         snla->v2d.tot.ymin=     0.0;
573         snla->v2d.tot.xmax= 1000.0;
574         snla->v2d.tot.ymax= 1000.0;
575         
576         snla->v2d.cur.xmin= -5.0;
577         snla->v2d.cur.ymin= 0.0;
578         snla->v2d.cur.xmax= 65.0;
579         snla->v2d.cur.ymax= 1000.0;
580         
581         snla->v2d.min[0]= 0.0;
582         snla->v2d.min[1]= 0.0;
583         
584         snla->v2d.max[0]= 1000.0;
585         snla->v2d.max[1]= 1000.0;
586         
587         snla->v2d.minzoom= 0.1F;
588         snla->v2d.maxzoom= 10;
589         
590         snla->v2d.scroll= R_SCROLL+B_SCROLL;
591         snla->v2d.keepaspect= 0;
592         snla->v2d.keepzoom= V2D_LOCKZOOM_Y;
593         snla->v2d.keeptot= 0;
594         
595         snla->lock = 0;
596 };
597
598 static void deselect_nlachannel_keys (int test)
599 {
600         Base                    *base;
601         int                             sel=1;
602         bActionChannel  *chan;
603         bActionStrip    *strip;
604         bConstraintChannel *conchan;
605         
606         /* Determine if this is selection or deselection */
607         if (test){
608                 for (base=G.scene->base.first; base && sel; base=base->next){
609                         
610                         /* Test object ipos */
611                         if (is_ipo_key_selected(base->object->ipo)){
612                                 sel = 0;
613                                 break;
614                         }
615                         
616                         /* Test object constraint ipos */
617                         if (sel){
618                                 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
619                                         if (is_ipo_key_selected(conchan->ipo)){
620                                                 sel=0;
621                                                 break;
622                                         }
623                                 }
624                         }
625                         
626                         /* Test action ipos */
627                         if (sel){
628                                 if (base->object->type==OB_ARMATURE && base->object->action){
629                                         for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
630                                                 if (is_ipo_key_selected(chan->ipo)){
631                                                         sel=0;
632                                                         break;
633                                                 }
634
635                                                 /* Test action constraints */
636                                                 if (sel){
637                                                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
638                                                                 if (is_ipo_key_selected(conchan->ipo)){
639                                                                         sel=0;
640                                                                         break;
641                                                                 }
642                                                         }
643                                                 }
644                                         }
645                                 }
646                         }
647                         
648                         /* Test NLA strips */
649                         if (sel){
650                                 if (base->object->type==OB_ARMATURE){
651                                         for (strip=base->object->nlastrips.first; strip; strip=strip->next){
652                                                 if (strip->flag & ACTSTRIP_SELECT){
653                                                         sel = 0;
654                                                         break;
655                                                 }
656                                         }
657                                 }
658                         }
659                 }
660         }
661         else
662                 sel=0;
663         
664         
665         /* Set the flags */
666         for (base=G.scene->base.first; base; base=base->next){
667                 /* Set the object ipos */
668                 set_ipo_key_selection(base->object->ipo, sel);
669
670                 
671                 /* Set the object constraint ipos */
672                 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
673                         set_ipo_key_selection(conchan->ipo, sel);                       
674                 }
675
676                 /* Set the action ipos */
677                 if (base->object->type==OB_ARMATURE && base->object->action){
678                         for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
679                                 set_ipo_key_selection(chan->ipo, sel);
680                                 /* Set the action constraint ipos */
681                                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
682                                         set_ipo_key_selection(conchan->ipo, sel);
683                         }
684                 }
685                 
686                 /* Set the nlastrips */
687                 if (base->object->type==OB_ARMATURE){
688                         for (strip=base->object->nlastrips.first; strip; strip=strip->next){
689                                 if (sel)
690                                         strip->flag |= ACTSTRIP_SELECT;
691                                 else
692                                         strip->flag &= ~ACTSTRIP_SELECT;
693                         }
694                 }
695         }
696 }
697
698
699 static void transform_nlachannel_keys(char mode)
700 {
701         Base *base;
702         TransVert *tv;
703         int /*sel=0,*/  i;
704         short   mvals[2], mvalc[2];
705         //      short    cent[2];
706         float   sval[2], cval[2], lastcval[2];
707         short   cancel=0;
708         float   fac=0.0F;
709         int             loop=1;
710         int             tvtot=0;
711         float   deltax, startx;
712         //      float   cenf[2];
713         int             invert=0, firsttime=1;
714         char    str[256];
715         bActionChannel *chan;
716         bActionStrip *strip;
717         bConstraintChannel *conchan;
718
719         /* Ensure that partial selections result in beztriple selections */
720         for (base=G.scene->base.first; base; base=base->next){
721
722                 /* Check object ipos */
723                 tvtot+=fullselect_ipo_keys(base->object->ipo);
724                 
725                 /* Check object constraint ipos */
726                 for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
727                         tvtot+=fullselect_ipo_keys(conchan->ipo);                       
728                 
729                 /* Check action ipos */
730                 if (base->object->type == OB_ARMATURE && base->object->action){
731                         for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
732                                 tvtot+=fullselect_ipo_keys(chan->ipo);
733                                 
734                                 /* Check action constraint ipos */
735                                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
736                                         tvtot+=fullselect_ipo_keys(conchan->ipo);
737                         }
738                 
739                 }
740
741                 /* Check nlastrips */
742                 if (base->object->type==OB_ARMATURE){
743                         for (strip=base->object->nlastrips.first; strip; strip=strip->next){
744                                 if (strip->flag & ACTSTRIP_SELECT)
745                                         tvtot+=2;
746                         }
747                 }
748         }
749         
750         /* If nothing is selected, bail out */
751         if (!tvtot)
752                 return;
753         
754         
755         /* Build the transvert structure */
756         tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert");
757         tvtot=0;
758         for (base=G.scene->base.first; base; base=base->next){
759                 /* Manipulate object ipos */
760                 tvtot=add_trans_ipo_keys(base->object->ipo, tv, tvtot);
761
762                 /* Manipulate object constraint ipos */
763                 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
764                         tvtot=add_trans_ipo_keys(conchan->ipo, tv, tvtot);
765
766                 /* Manipulate action ipos */
767                 if (base->object->type==OB_ARMATURE && base->object->action){
768                         for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
769                                 tvtot=add_trans_ipo_keys(chan->ipo, tv, tvtot);
770
771                                 /* Manipulate action constraint ipos */
772                                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
773                                         tvtot=add_trans_ipo_keys(conchan->ipo, tv, tvtot);
774                         }
775                 }
776
777                 /* Manipulate nlastrips */
778                 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
779                         if (strip->flag & ACTSTRIP_SELECT){
780                                 tv[tvtot+0].val=&strip->start;
781                                 tv[tvtot+1].val=&strip->end;
782                                 
783                                 tv[tvtot+0].oldval = strip->start;
784                                 tv[tvtot+1].oldval = strip->end;
785                                 
786                                 tvtot+=2;
787                         }
788                 }
789         }
790         
791         /* Do the event loop */
792         //      cent[0] = curarea->winx + (G.snla->v2d.hor.xmax)/2;
793         //      cent[1] = curarea->winy + (G.snla->v2d.hor.ymax)/2;
794         
795         //      areamouseco_to_ipoco(cent, &cenf[0], &cenf[1]);
796         
797         getmouseco_areawin (mvals);
798         areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]);
799         
800         startx=sval[0];
801         while (loop) {
802                 /*              Get the input */
803                 /*              If we're cancelling, reset transformations */
804                 /*                      Else calc new transformation */
805                 /*              Perform the transformations */
806                 while (qtest()) {
807                         short val;
808                         unsigned short event= extern_qread(&val);
809                         
810                         if (val) {
811                                 switch (event) {
812                                 case LEFTMOUSE:
813                                 case SPACEKEY:
814                                 case RETKEY:
815                                         loop=0;
816                                         break;
817                                 case XKEY:
818                                         break;
819                                 case ESCKEY:
820                                 case RIGHTMOUSE:
821                                         cancel=1;
822                                         loop=0;
823                                         break;
824                                 default:
825                                         arrows_move_cursor(event);
826                                         break;
827                                 };
828                         }
829                 }
830                 
831                 if (cancel) {
832                         for (i=0; i<tvtot; i++) {
833                                 if (tv[i].loc){
834                                         tv[i].loc[0]=tv[i].oldloc[0];
835                                         tv[i].loc[1]=tv[i].oldloc[1];
836                                 }
837                                 if (tv[i].val)
838                                         tv[i].val[0]=tv[i].oldval;
839                         }
840                 }
841                 else {
842                         getmouseco_areawin (mvalc);
843                         areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]);
844                         
845                         if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
846                                 PIL_sleep_ms(1);
847                         }
848                         else {
849                                 for (i=0; i<tvtot; i++){
850                                         if (tv[i].loc)
851                                                 tv[i].loc[0]=tv[i].oldloc[0];
852                                         if (tv[i].val)
853                                                 tv[i].val[0]=tv[i].oldval;
854                                         
855                                         switch (mode){
856                                         case 'g':
857                                                 deltax = cval[0]-sval[0];
858                                                 fac= deltax;
859                                                 
860                                                 apply_keyb_grid(&fac, 0.0F, 1.0F, 0.1F, U.flag & AUTOGRABGRID);
861                                                 
862                                                 if (tv[i].loc)
863                                                         tv[i].loc[0]+=fac;
864                                                 if (tv[i].val)
865                                                         tv[i].val[0]+=fac;
866                                                 break;
867                                         case 's': 
868                                                 startx=mvals[0]-(NLAWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
869                                                 deltax=mvalc[0]-(NLAWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
870                                                 fac= (float)fabs(deltax/startx);
871                                                 
872                                                 apply_keyb_grid(&fac, 0.0F, 0.2F, 0.1F, U.flag & AUTOSIZEGRID);
873                                                 
874                                                 if (invert){
875                                                         if (i % 03 == 0){
876                                                                 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i+2].oldloc));
877                                                         }
878                                                         if (i % 03 == 2){
879                                                                 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i-2].oldloc));
880                                                         }
881                                                         
882                                                         fac*=-1;
883                                                 }
884                                                 startx= (G.scene->r.cfra);
885                                                 
886                                                 if (tv[i].loc){
887                                                         tv[i].loc[0]-= startx;
888                                                         tv[i].loc[0]*=fac;
889                                                         tv[i].loc[0]+= startx;
890                                                 }
891                                                 if (tv[i].val){
892                                                         tv[i].val[0]-= startx;
893                                                         tv[i].val[0]*=fac;
894                                                         tv[i].val[0]+= startx;
895                                                 }
896                                                 
897                                                 break;
898                                         }
899                                 }
900                         }
901                         
902                         if (mode=='s'){
903                                 sprintf(str, "sizeX: %.3f", fac);
904                                 headerprint(str);
905                         }
906                         else if (mode=='g'){
907                                 sprintf(str, "deltaX: %.3f", fac);
908                                 headerprint(str);
909                         }
910                         
911                         if (G.snla->lock){
912                                 allqueue (REDRAWVIEW3D, 0);
913                                 allqueue (REDRAWNLA, 0);
914                                 allqueue (REDRAWIPO, 0);
915                                 force_draw_all();
916                         }
917                         else {
918                                 addqueue (curarea->win, REDRAWALL, 0);
919                                 force_draw ();
920                         }
921                 }
922                 
923                 lastcval[0]= cval[0];
924                 lastcval[1]= cval[1];
925                 firsttime= 0;
926         }
927         
928         allspace(REMAKEALLIPO, 0);
929         allqueue (REDRAWVIEW3D, 0);
930         allqueue (REDRAWNLA, 0);
931         allqueue (REDRAWIPO, 0);
932         MEM_freeN (tv);
933 }
934
935 static void delete_nlachannel_keys(void)
936 {
937         Base *base;
938         bActionChannel *chan;
939         bConstraintChannel *conchan;
940         bActionStrip *strip, *nextstrip;
941         
942         if (!okee("Erase selected keys"))
943                 return;
944         
945         for (base = G.scene->base.first; base; base=base->next){
946
947                 /* Delete object ipos */
948                 delete_ipo_keys(base->object->ipo);
949                 
950                 /* Delete object constraint keys */
951                 for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
952                         delete_ipo_keys(conchan->ipo);
953
954                 /* Delete NLA strips */
955                 if (base->object->type==OB_ARMATURE){
956                         for (strip = base->object->nlastrips.first; strip; strip=nextstrip){
957                                 nextstrip=strip->next;
958                                 if (strip->flag & ACTSTRIP_SELECT){
959                                         free_actionstrip(strip);
960                                         BLI_remlink(&base->object->nlastrips, strip);
961                                         MEM_freeN(strip);
962                                 }
963                         }
964                 }
965                 
966                 /* Delete action ipos */
967                 if (base->object->type==OB_ARMATURE && base->object->action){
968                         for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
969                                 delete_ipo_keys(chan->ipo);
970                                 /* Delete action constraint keys */
971                                 for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
972                                         delete_ipo_keys(conchan->ipo);
973                         }
974                 }
975         }
976         
977         allspace(REMAKEALLIPO, 0);
978         allqueue(REDRAWNLA, 0);
979         allqueue(REDRAWIPO, 0);
980 }
981
982 static void duplicate_nlachannel_keys(void)
983 {
984         Base *base;
985         bActionChannel *chan;
986         bConstraintChannel *conchan;
987         bActionStrip *strip, *laststrip;
988         
989         /* Find selected items */
990         for (base = G.scene->base.first; base; base=base->next){
991                 /* Duplicate object keys */
992                 duplicate_ipo_keys(base->object->ipo);
993                 
994                 /* Duplicate object constraint keys */
995                 for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
996                         duplicate_ipo_keys(conchan->ipo);
997
998                 /* Duplicate nla strips */
999                 if (base->object->type == OB_ARMATURE){
1000                         laststrip = base->object->nlastrips.last;
1001                         for (strip=base->object->nlastrips.first; strip; strip=strip->next){
1002                                 if (strip->flag & ACTSTRIP_SELECT){
1003                                         bActionStrip *newstrip;
1004                                         
1005                                         copy_actionstrip(&newstrip, &strip);
1006                                         
1007                                         BLI_addtail(&base->object->nlastrips, newstrip);
1008                                         
1009                                         strip->flag &= ~ACTSTRIP_SELECT;
1010                                         newstrip->flag |= ACTSTRIP_SELECT;
1011                                         
1012                                 }
1013                                 if (strip==laststrip)
1014                                         break;
1015                         }
1016                 }
1017                 
1018                 /* Duplicate actionchannel keys */
1019                 if (base->object->type == OB_ARMATURE && base->object->action){
1020                         for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
1021                                 duplicate_ipo_keys(chan->ipo);
1022                                 /* Duplicate action constraint keys */
1023                                 for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1024                                         duplicate_ipo_keys(conchan->ipo);
1025                         }
1026                 }
1027         }
1028         
1029         transform_nlachannel_keys ('g');
1030 }
1031
1032 static void borderselect_nla(void)
1033
1034         Base *base;
1035         rcti rect;
1036         rctf rectf;
1037         int val;                
1038         short   mval[2];
1039         float   ymin, ymax;
1040         bActionStrip *strip;
1041         bConstraintChannel *conchan;
1042         
1043         val= get_border (&rect, 3);
1044         
1045         if (val){
1046                 mval[0]= rect.xmin;
1047                 mval[1]= rect.ymin+2;
1048                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1049                 mval[0]= rect.xmax;
1050                 mval[1]= rect.ymax-2;
1051                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1052                 
1053                 ymax = count_nla_levels();
1054                 ymax*= (NLACHANNELHEIGHT+NLACHANNELSKIP);
1055                 
1056                 for (base=G.scene->base.first; base; base=base->next){
1057                         /* Check object ipos */
1058                         if (nla_filter(base, 0)){
1059                                 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1060                                 if (base->object->ipo){
1061                                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
1062                                                 borderselect_ipo_key(base->object->ipo, rectf.xmin, rectf.xmax, val);
1063                                 }
1064                                 ymax=ymin;
1065
1066                                 /* Check object constraint ipos */
1067                                 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
1068                                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1069                                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
1070                                                 borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, val);
1071                                         ymax=ymin;
1072                                 }
1073
1074                                 /* Check action ipos */
1075                                 if (ACTIVE_ARMATURE(base)){
1076                                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1077                                         if (base->object->action){
1078                                                 bActionChannel *chan;
1079                                                 
1080                                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1081                                                         for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
1082                                                                 borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax, val);
1083                                                                 /* Check action constraint ipos */
1084                                                                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1085                                                                         borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, val);
1086                                                         }
1087                                                 }
1088                                         }
1089                                         ymax=ymin;
1090                                 }       /* End of if armature */
1091                                 
1092                                 /* Skip nlastrips */
1093                                 if (base->object->type==OB_ARMATURE){
1094                                         for (strip=base->object->nlastrips.first; strip; strip=strip->next){
1095                                                 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1096                                                 //
1097                                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1098                                                         if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
1099                                                                 if (val==1)
1100                                                                         strip->flag |= ACTSTRIP_SELECT;
1101                                                                 else
1102                                                                         strip->flag &= ~ACTSTRIP_SELECT;
1103                                                         }
1104                                                 }
1105                                                 
1106                                                 ymax=ymin;
1107                                         }
1108                                 }
1109                                 
1110                         }       /* End of object filter */
1111                 }       
1112                 allqueue(REDRAWNLA, 0);
1113                 allqueue(REDRAWACTION, 0);
1114                 allqueue(REDRAWIPO, 0);
1115         }
1116 }
1117
1118 static void mouse_nla(void)
1119 {
1120         short sel;
1121         float   selx;
1122         short   mval[2];
1123         Base *base;
1124         bAction *act;
1125         bActionChannel *chan;
1126         bActionStrip *rstrip;
1127         bConstraintChannel *conchan;
1128         
1129         getmouseco_areawin (mval);
1130         
1131         /* Try object ipo selection */
1132         base=get_nearest_nlachannel_ob_key(&selx, &sel);
1133         if (base){
1134                 if (!(G.qual & LR_SHIFTKEY)){
1135                         deselect_nlachannel_keys(0);
1136                         sel = 0;
1137                 }
1138                 
1139                 select_ipo_key(base->object->ipo, selx, sel);
1140                 
1141                 /* Try object constraint selection */
1142                 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
1143                         select_ipo_key(conchan->ipo, selx, sel);
1144                 
1145                 
1146                 allqueue(REDRAWIPO, 0);
1147                 allqueue(REDRAWVIEW3D, 0);
1148                 allqueue(REDRAWNLA, 0);
1149                 return;
1150         }
1151
1152         /* Try action ipo selection */
1153         act=get_nearest_nlachannel_ac_key(&selx, &sel);
1154         if (act){
1155                 if (!(G.qual & LR_SHIFTKEY)){
1156                         deselect_nlachannel_keys(0);
1157                         sel = 0;
1158                 }
1159                 
1160                 for (chan=act->chanbase.first; chan; chan=chan->next){
1161                         select_ipo_key(chan->ipo, selx, sel);
1162                         /* Try action constraint selection */
1163                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1164                                 select_ipo_key(conchan->ipo, selx, sel);
1165                 }
1166                 
1167                 allqueue(REDRAWIPO, 0);
1168                 allqueue(REDRAWVIEW3D, 0);
1169                 allqueue(REDRAWNLA, 0);
1170                 return;
1171         }
1172         
1173         /* Try nla strip selection */
1174         base=get_nearest_nlastrip(&rstrip, &sel);
1175         if (base){
1176                 if (!(G.qual & LR_SHIFTKEY)){
1177                         deselect_nlachannel_keys(0);
1178                         sel = 0;
1179                 }
1180                 
1181                 if (sel)
1182                         rstrip->flag &= ~ACTSTRIP_SELECT;
1183                 else
1184                         rstrip->flag |= ACTSTRIP_SELECT;
1185                 
1186                 allqueue(REDRAWIPO, 0);
1187                 allqueue(REDRAWVIEW3D, 0);
1188                 allqueue(REDRAWNLA, 0);
1189                 return;
1190                 
1191         }
1192         
1193 }
1194
1195 static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel)
1196 /* This function is currently more complicated than it seems like it should be.
1197 * However, this will be needed once the nla strip timeline is more complex */
1198 {
1199         Base *base, *firstbase=NULL;
1200         short mval[2];
1201         short foundsel = 0;
1202         rctf    rectf;
1203         float ymin, ymax;
1204         bActionStrip *strip, *firststrip, *foundstrip;
1205         
1206         getmouseco_areawin (mval);
1207         
1208         mval[0]-=7;
1209         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1210         
1211         mval[0]+=14;
1212         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1213         
1214         ymax = count_nla_levels();
1215         ymax*=(NLACHANNELHEIGHT + NLACHANNELSKIP);
1216         
1217         for (base = G.scene->base.first; base; base=base->next){
1218                 if (nla_filter(base, 0)){
1219                         /* Skip object ipos */
1220                         //      if (base->object->ipo)
1221                         ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
1222                         
1223                         if (base->object->type==OB_ARMATURE){
1224                                 /* Skip action ipos */
1225                                 if (base->object->action)
1226                                         ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
1227                                 
1228                                 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
1229                                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1230                                         /* Do Ytest */
1231                                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1232                                                 /* Do XTest */
1233                                                 if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
1234                                                         if (!firstbase){
1235                                                                 firstbase=base;
1236                                                                 firststrip=strip;
1237                                                                 *sel = strip->flag & ACTSTRIP_SELECT;
1238                                                         }
1239                                                         
1240                                                         if (strip->flag & ACTSTRIP_SELECT){ 
1241                                                                 if (!foundsel){
1242                                                                         foundsel=1;
1243                                                                         foundstrip = strip;
1244                                                                 }
1245                                                         }
1246                                                         else if (foundsel && strip != foundstrip){
1247                                                                 *rstrip=strip;
1248                                                                 *sel = 0;
1249                                                                 return base;
1250                                                         }
1251                                                 }
1252                                         }
1253                                         ymax=ymin;
1254                                 }
1255                         }
1256                 }
1257         }
1258         *rstrip=firststrip;
1259         return firstbase;
1260 }
1261
1262 static Base *get_nearest_nlachannel_ob_key (float *index, short *sel)
1263 {
1264         Base *base;
1265         IpoCurve *icu;
1266         Base *firstbase=NULL;
1267         bConstraintChannel *conchan;
1268         int     foundsel=0;
1269         float firstvert=-1, foundx=-1;
1270         int i;
1271         short mval[2];
1272         float ymin, ymax;
1273         rctf    rectf;
1274         
1275         *index=0;
1276         
1277         getmouseco_areawin (mval);
1278         
1279         mval[0]-=7;
1280         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1281         
1282         mval[0]+=14;
1283         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1284         
1285         ymax = count_nla_levels();
1286         
1287         ymax*=(NLACHANNELHEIGHT + NLACHANNELSKIP);
1288         
1289         *sel=0;
1290         
1291         for (base=G.scene->base.first; base; base=base->next){
1292                 /* Handle object ipo selection */
1293                 if (nla_filter(base, 0)){
1294                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1295                         if (base->object->ipo){
1296                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1297                                         for (icu=base->object->ipo->curve.first; icu; icu=icu->next){
1298                                                 for (i=0; i<icu->totvert; i++){
1299                                                         if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
1300                                                                 if (!firstbase){
1301                                                                         firstbase=base;
1302                                                                         firstvert=icu->bezt[i].vec[1][0];
1303                                                                         *sel = icu->bezt[i].f2 & 1;     
1304                                                                 }
1305                                                                 
1306                                                                 if (icu->bezt[i].f2 & 1){ 
1307                                                                         if (!foundsel){
1308                                                                                 foundsel=1;
1309                                                                                 foundx = icu->bezt[i].vec[1][0];
1310                                                                         }
1311                                                                 }
1312                                                                 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
1313                                                                         *index=icu->bezt[i].vec[1][0];
1314                                                                         *sel = 0;
1315                                                                         return base;
1316                                                                 }
1317                                                         }
1318                                                 }
1319                                         }
1320                                 }
1321                         }
1322                 
1323                         ymax=ymin;
1324
1325                         /* Handle object constraint ipos */
1326                         for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
1327                                 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1328                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1329                                         for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
1330                                                 for (i=0; i<icu->totvert; i++){
1331                                                         if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
1332                                                                 if (!firstbase){
1333                                                                         firstbase=base;
1334                                                                         firstvert=icu->bezt[i].vec[1][0];
1335                                                                         *sel = icu->bezt[i].f2 & 1;     
1336                                                                 }
1337                                                                 
1338                                                                 if (icu->bezt[i].f2 & 1){ 
1339                                                                         if (!foundsel){
1340                                                                                 foundsel=1;
1341                                                                                 foundx = icu->bezt[i].vec[1][0];
1342                                                                         }
1343                                                                 }
1344                                                                 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
1345                                                                         *index=icu->bezt[i].vec[1][0];
1346                                                                         *sel = 0;
1347                                                                         return base;
1348                                                                 }
1349                                                         }
1350                                                 }
1351                                         }
1352                                 }
1353                                 ymax=ymin;
1354                         }
1355
1356                         /* Skip action ipos */
1357                         if (ACTIVE_ARMATURE(base)){
1358                                 ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
1359                         }
1360                         /* Skip nlastrips */
1361                         if (base->object->type==OB_ARMATURE){
1362                                 ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
1363                         }
1364                 }
1365         }       
1366         
1367         *index=firstvert;
1368         return firstbase;
1369 }
1370
1371 static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel)
1372 {
1373         Base *base;
1374         IpoCurve *icu;
1375         bAction *firstact=NULL;
1376         int     foundsel=0;
1377         float firstvert=-1, foundx=-1;
1378         int i;
1379         short mval[2];
1380         float ymin, ymax;
1381         rctf    rectf;
1382         bActionChannel *chan;
1383         bConstraintChannel *conchan;
1384         
1385         *index=0;
1386         
1387         getmouseco_areawin (mval);
1388         
1389         mval[0]-=7;
1390         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1391         
1392         mval[0]+=14;
1393         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1394         
1395         ymax = count_nla_levels();
1396         
1397         ymax*=(NLACHANNELHEIGHT + NLACHANNELSKIP);
1398         
1399         *sel=0;
1400         
1401         for (base=G.scene->base.first; base; base=base->next){
1402                 /* Handle object ipo selection */
1403                 if (nla_filter(base, 0)){
1404                         /* Skip object ipo */
1405                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1406                         ymax=ymin;
1407                         
1408                         /* Handle action ipos */
1409                         if (ACTIVE_ARMATURE(base)){
1410                                 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1411                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1412                                         for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
1413                                                 for (icu=chan->ipo->curve.first; icu; icu=icu->next){
1414                                                         for (i=0; i<icu->totvert; i++){
1415                                                                 if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
1416                                                                         if (!firstact){
1417                                                                                 firstact=base->object->action;
1418                                                                                 firstvert=icu->bezt[i].vec[1][0];
1419                                                                                 *sel = icu->bezt[i].f2 & 1;     
1420                                                                         }
1421                                                                         
1422                                                                         if (icu->bezt[i].f2 & 1){ 
1423                                                                                 if (!foundsel){
1424                                                                                         foundsel=1;
1425                                                                                         foundx = icu->bezt[i].vec[1][0];
1426                                                                                 }
1427                                                                         }
1428                                                                         else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
1429                                                                                 *index=icu->bezt[i].vec[1][0];
1430                                                                                 *sel = 0;
1431                                                                                 return base->object->action;
1432                                                                         }
1433                                                                 }
1434                                                         }
1435                                                 }
1436                                                 
1437                                                 
1438                                                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1439                                                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1440                                                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1441                                                                 for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
1442                                                                         for (i=0; i<icu->totvert; i++){
1443                                                                                 if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
1444                                                                                         if (!firstact){
1445                                                                                                 firstact=base->object->action;
1446                                                                                                 firstvert=icu->bezt[i].vec[1][0];
1447                                                                                                 *sel = icu->bezt[i].f2 & 1;     
1448                                                                                         }
1449                                                                                         
1450                                                                                         if (icu->bezt[i].f2 & 1){ 
1451                                                                                                 if (!foundsel){
1452                                                                                                         foundsel=1;
1453                                                                                                         foundx = icu->bezt[i].vec[1][0];
1454                                                                                                 }
1455                                                                                         }
1456                                                                                         else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
1457                                                                                                 *index=icu->bezt[i].vec[1][0];
1458                                                                                                 *sel = 0;
1459                                                                                                 return base->object->action;
1460                                                                                         }
1461                                                                                 }
1462                                                                         }
1463                                                                 }
1464                                                         }
1465                                                         ymax=ymin;
1466                                                 }
1467                                         
1468                                         
1469                                         }
1470                                 }                       
1471                                 ymax=ymin;
1472                         }
1473                         
1474                         /* Skip nlastrips */
1475                         if (base->object->type==OB_ARMATURE){
1476                                 ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
1477                         }
1478                 }
1479         }       
1480         
1481         *index=firstvert;
1482         return firstact;
1483 }
1484
1485 static bActionStrip *get_active_nlastrip(void)
1486 /* For now just returns the first selected strip */
1487 {
1488         Base *base;
1489         bActionStrip *strip;
1490         
1491         for (base=G.scene->base.first; base; base=base->next){
1492                 if (nla_filter(base, 0) && base->object->type==OB_ARMATURE){
1493                         for (strip=base->object->nlastrips.first; strip; strip=strip->next){
1494                                 if (strip->flag & ACTSTRIP_SELECT)
1495                                         return strip;
1496                         }
1497                 }
1498         }
1499         
1500         return NULL;
1501 }
1502
1503 void clever_numbuts_nla(void){
1504         bActionStrip *strip;
1505         int but=0;
1506                 
1507         /* Determine if an nla strip has been selected */
1508         strip = get_active_nlastrip();
1509         if (!strip)
1510                 return;
1511         
1512         add_numbut(but++, LABEL, "Timeline Range:", 1.0, 18000.0, 0, 0);
1513         add_numbut(but++, NUM|FLO, "Strip Start:", 1.0, 18000.0, &strip->start, "First frame in the timeline");
1514         add_numbut(but++, NUM|FLO, "Strip End:", 1.0, 18000.0, &strip->end, "Last frame in the timeline");
1515         add_numbut(but++, LABEL, "Action Range:", 1.0, 18000.0, 0, 0);
1516         add_numbut(but++, NUM|FLO, "Action Start:", 1.0, 18000.0, &strip->actstart, "First frame of the action to map to the playrange");
1517         add_numbut(but++, NUM|FLO, "Action End:", 1.0, 18000.0, &strip->actend, "Last frame of the action to map to the playrange");
1518         add_numbut(but++, LABEL, "Blending:", 1.0, 18000.0, 0, 0);
1519         add_numbut(but++, NUM|FLO, "Blendin:", 0.0, 18000.0, &strip->blendin, "Number of frames of ease-in");
1520         add_numbut(but++, NUM|FLO, "Blendout:", 0.0, 18000.0, &strip->blendout, "Number of frames of ease-out");
1521         add_numbut(but++, LABEL, "Options:", 1.0, 18000.0, 0, 0);
1522         add_numbut(but++, NUM|FLO, "Repeat:", 0.0001, 18000.0, &strip->repeat, "Number of times the action should repeat");
1523         add_numbut(but++, NUM|FLO, "Stride:", 0.0001, 1000.0, &strip->stridelen, "Distance covered by one complete cycle of the action specified in the Action Range");
1524         {
1525                 /* STUPID HACK BECAUSE NUMBUTS ARE BROKEN WITH MULTIPLE TOGGLES */
1526                 short hold= (strip->flag & ACTSTRIP_HOLDLASTFRAME) ? 1 : 0;
1527                 short frompath=(strip->flag & ACTSTRIP_USESTRIDE) ? 1 : 0;
1528
1529                 add_numbut(but++, TOG|SHO, "Use Path", 0, 0, &frompath, "Plays action based on position on path & stride length.  Only valid for armatures that are parented to a path");
1530                 add_numbut(but++, TOG|SHO, "Hold", 0, 0, &hold, "Toggles whether or not to continue displaying the last frame past the end of the strip");
1531                 add_numbut(but++, TOG|SHO, "Add", 0, 0, &strip->mode, "Toggles additive blending mode");
1532                 
1533                 do_clever_numbuts("Action", but, REDRAW);
1534                 
1535                 /* STUPID HACK BECAUSE NUMBUTS ARE BROKEN WITH MULTIPLE TOGGLES */
1536                 if (hold) strip->flag |= ACTSTRIP_HOLDLASTFRAME;
1537                 else strip->flag &= ~ACTSTRIP_HOLDLASTFRAME;
1538
1539                 if (frompath) strip->flag |= ACTSTRIP_USESTRIDE;
1540                 else strip->flag &= ~ACTSTRIP_USESTRIDE;
1541                 
1542         }
1543
1544         if (strip->end<strip->start)
1545                 strip->end=strip->start;
1546
1547
1548         if (strip->blendin>(strip->end-strip->start))
1549                 strip->blendin = strip->end-strip->start;
1550
1551         if (strip->blendout>(strip->end-strip->start))
1552                 strip->blendout = strip->end-strip->start;
1553
1554         if (strip->blendin > (strip->end-strip->start-strip->blendout))
1555                 strip->blendin = (strip->end-strip->start-strip->blendout);
1556
1557         if (strip->blendout > (strip->end-strip->start-strip->blendin))
1558                 strip->blendout = (strip->end-strip->start-strip->blendin);
1559         
1560         
1561         update_for_newframe();
1562         allqueue (REDRAWNLA, 0);
1563         allqueue (REDRAWVIEW3D, 0);
1564 }       
1565
1566 static void deselect_nlachannels(int test){
1567         int sel = 1;
1568         Base *base;
1569         bConstraintChannel *conchan;
1570
1571         if (test){
1572                 for (base=G.scene->base.first; base; base=base->next){
1573                         /* Check base flags for previous selection */
1574                         if (base->flag & SELECT){
1575                                 sel=0;
1576                                 break;
1577                         }
1578
1579                         /* Check constraint flags for previous selection */
1580                         for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
1581                                 if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1582                                         sel=0;
1583                                         base = G.scene->base.last;
1584                                         break;
1585                                 }
1586                         }
1587                 }
1588         }
1589         else
1590                 sel = 0;
1591
1592         /* Select objects */
1593         for (base=G.scene->base.first; base; base=base->next){
1594                 if (sel){
1595                         if (nla_filter(base, 0))
1596                                 base->flag |= SELECT;
1597                 }
1598                 else
1599                         base->flag &= ~SELECT;
1600
1601                 /* Select constraint channels */
1602                 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
1603                         if (sel){
1604                                 if (nla_filter(base, 0))
1605                                         conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
1606                         }
1607                         else
1608                                 conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
1609                 }
1610         }       
1611 }
1612
1613 static void delete_nlachannels(void){
1614         Base *base;
1615         bConstraintChannel *conchan, *nextchan;
1616         int sel=0;
1617
1618         /* See if there is anything selected */
1619         for (base = G.scene->base.first; base && (!sel); base=base->next){
1620                 /* Check constraints */
1621                 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
1622                         if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1623                                 sel = 1;
1624                                 break;
1625                         }
1626                 }
1627         }
1628
1629         if (!sel)
1630                 return;
1631
1632         if (okee ("Delete selected channels")){
1633                 for (base=G.scene->base.first; base; base=base->next){
1634                         for (conchan=base->object->constraintChannels.first; conchan; conchan=nextchan){
1635                                 nextchan = conchan->next;
1636                                 
1637                                 if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
1638                                         /* If we're the active constraint, unlink us */
1639                                         if (conchan==base->object->activecon)
1640                                                 base->object->activecon = NULL;
1641                                         
1642                                         if (conchan->ipo)
1643                                                 conchan->ipo->id.us--;
1644                                         BLI_freelinkN(&base->object->constraintChannels, conchan);
1645                                 }
1646                         }
1647                 }
1648         }
1649 }