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