Orange; stuff for the animation department!
[blender.git] / source / blender / src / editnla.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL 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. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL *****
28  *
29  * This file is a horrible mess: An attmept to cram some
30  * final functionality into blender before it is too late.
31  *
32  * Hopefully it can be tidied up at a later date...
33 */
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include <math.h>
38
39 #include "PIL_time.h"
40
41 #include "MEM_guardedalloc.h"
42
43 #include "BLI_blenlib.h"
44
45 #include "DNA_action_types.h"
46 #include "DNA_constraint_types.h"
47 #include "DNA_curve_types.h"
48 #include "DNA_ipo_types.h"
49 #include "DNA_object_types.h"
50 #include "DNA_nla_types.h"
51 #include "DNA_screen_types.h"
52 #include "DNA_space_types.h"
53 #include "DNA_scene_types.h"
54 #include "DNA_userdef_types.h"
55
56 #include "BKE_action.h"
57 #include "BKE_depsgraph.h"
58 #include "BKE_group.h"
59 #include "BKE_global.h"
60 #include "BKE_ipo.h"
61 #include "BKE_library.h"
62 #include "BKE_main.h"
63 #include "BKE_nla.h"
64
65 #include "BIF_screen.h"
66 #include "BIF_interface.h"
67 #include "BIF_butspace.h"
68 #include "BIF_space.h"
69 #include "BIF_mywindow.h"
70 #include "BIF_editview.h"
71 #include "BIF_toolbox.h"
72 #include "BIF_editnla.h"
73
74 #include "BSE_editipo.h"
75 #include "BSE_editnla_types.h"
76 #include "BSE_headerbuttons.h"
77 #include "BSE_drawipo.h"
78 #include "BSE_trans_types.h"
79 #include "BSE_edit.h"
80 #include "BSE_filesel.h"
81 #include "BDR_editobject.h"
82 #include "BSE_drawnla.h"
83
84 #include "blendef.h"
85 #include "mydevice.h"
86
87 #ifdef HAVE_CONFIG_H
88 #include <config.h>
89 #endif
90
91 /* Note: A lot of these pretty much duplicate the behaviour of the
92 action windows.  The functions should be shared, not copy-pasted */
93
94 static void mouse_nla(int selectmode);
95 static Base *get_nearest_nlachannel_ob_key (float *index, short *sel);
96 static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel);
97 static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel);
98 static void mouse_nlachannels(short mval[2]);
99 static void convert_nla(short mval[2]);
100
101 /* ******************** SPACE: NLA ********************** */
102
103 void shift_nlastrips_up(void) {
104         
105         Base *base;
106         bActionStrip *strip, *prevstrip;
107
108         for (base=G.scene->base.first; base; base=base->next) {
109                 for (strip = base->object->nlastrips.first; 
110                          strip; strip=strip->next){
111                         if (strip->flag & ACTSTRIP_SELECT) {
112                                 if ( (prevstrip = strip->prev) ) {
113                                         if (prevstrip->prev)
114                                                 prevstrip->prev->next = strip;
115                                         if (strip->next)
116                                                 strip->next->prev = prevstrip;
117                                         strip->prev = prevstrip->prev;
118                                         prevstrip->next = strip->next;
119                                         strip->next = prevstrip;
120                                         prevstrip->prev = strip;
121
122                                         if (prevstrip == base->object->nlastrips.first)
123                                                 base->object->nlastrips.first = strip;
124                                         if (strip == base->object->nlastrips.last)
125                                                 base->object->nlastrips.last = prevstrip;
126
127                                         strip = prevstrip;
128                                 }
129                                 else {
130                                         break;
131                                 }
132                         }
133                 }
134         }
135         BIF_undo_push("Shift NLA strip");
136         allqueue (REDRAWNLA, 0);
137
138 }
139
140 void shift_nlastrips_down(void) {
141         
142         Base *base;
143         bActionStrip *strip, *nextstrip;
144
145         for (base=G.scene->base.first; base; base=base->next) {
146                 for (strip = base->object->nlastrips.last; 
147                          strip; strip=strip->prev){
148                         if (strip->flag & ACTSTRIP_SELECT) {
149                                 if ( (nextstrip = strip->next) ) {
150                                         if (nextstrip->next)
151                                                 nextstrip->next->prev = strip;
152                                         if (strip->prev)
153                                                 strip->prev->next = nextstrip;
154                                         strip->next = nextstrip->next;
155                                         nextstrip->prev = strip->prev;
156                                         strip->prev = nextstrip;
157                                         nextstrip->next = strip;
158
159                                         if (nextstrip == base->object->nlastrips.last)
160                                                 base->object->nlastrips.last = strip;
161                                         if (strip == base->object->nlastrips.first)
162                                                 base->object->nlastrips.first = nextstrip;
163
164                                         strip = nextstrip;
165                                 }
166                                 else {
167                                         break;
168                                 }
169                         }
170                 }
171         }
172         
173         BIF_undo_push("Shift NLA strips");
174         allqueue (REDRAWNLA, 0);
175 }
176
177 void synchronize_action_strips(void)
178 {
179         Base *base;
180         bActionStrip *strip;
181         
182         for (base=G.scene->base.first; base; base=base->next) {
183                 for (strip = base->object->nlastrips.last; strip; strip=strip->prev) {
184                         if (strip->flag & ACTSTRIP_LOCK_ACTION) {
185                                 float actstart, actend;
186                                 
187                                 calc_action_range(strip->act, &actstart, &actend);
188                                 
189                                 if(strip->actstart!=actstart || strip->actend!=actend) {
190                                         float mapping= (strip->end - strip->start)/(strip->actend - strip->actstart);
191                                         
192                                         strip->start+= mapping*(actstart - strip->actstart);
193                                         strip->end+= mapping*(actend - strip->actend);
194                                         
195                                         strip->actstart= actstart;
196                                         strip->actend= actend;
197                                 }
198                         }
199                 }
200         }
201         
202 }
203
204 void reset_action_strips(int val)
205 {
206         Base *base;
207         bActionStrip *strip;
208         
209         for (base=G.scene->base.first; base; base=base->next) {
210                 for (strip = base->object->nlastrips.last; strip; strip=strip->prev) {
211                         if (strip->flag & ACTSTRIP_SELECT) {
212                                 if(val==2) {
213                                         calc_action_range(strip->act, &strip->actstart, &strip->actend);
214                                 }
215                                 else if(val==1) {
216                                         float mapping= (strip->actend - strip->actstart)/(strip->end - strip->start);
217                                         
218                                         strip->end= strip->start + mapping*(strip->end - strip->start);
219                                 }
220                                 base->object->ctime= -1234567.0f;       // eveil! 
221                                 DAG_object_flush_update(G.scene, base->object, OB_RECALC_OB|OB_RECALC_DATA);
222                         }
223                 }
224         }
225         BIF_undo_push("Reset NLA strips");
226         allqueue (REDRAWVIEW3D, 0);
227         allqueue (REDRAWACTION, 0);
228         allqueue (REDRAWNLA, 0);
229 }
230
231 void snap_action_strips(void)
232 {
233         Base *base;
234         bActionStrip *strip;
235         
236         for (base=G.scene->base.first; base; base=base->next) {
237                 for (strip = base->object->nlastrips.last; strip; strip=strip->prev) {
238                         if (strip->flag & ACTSTRIP_SELECT) {
239                                 strip->start= floor(strip->start+0.5);
240                                 strip->end= floor(strip->end+0.5);
241                         }
242                 }
243         }
244         BIF_undo_push("Snap NLA strips");
245         allqueue (REDRAWVIEW3D, 0);
246         allqueue (REDRAWACTION, 0);
247         allqueue (REDRAWNLA, 0);
248 }
249
250 static void set_active_strip(Object *ob, bActionStrip *act)
251 {
252         bActionStrip *strip;
253         
254         for (strip = ob->nlastrips.first; strip; strip=strip->next)
255                 strip->flag &= ~ACTSTRIP_ACTIVE;
256         
257         if(act) {
258                 act->flag |= ACTSTRIP_ACTIVE;
259         
260                 if(ob->action!=act->act) {
261                         if(ob->action) ob->action->id.us--;
262                         if(act->act->id.lib) {
263                                 ob->action= NULL;
264                         }
265                         else {
266                                 ob->action= act->act;
267                                 id_us_plus(&ob->action->id);
268                         }                       
269                         allqueue(REDRAWIPO, 0);
270                         allqueue(REDRAWVIEW3D, 0);
271                         allqueue(REDRAWACTION, 0);
272                         allqueue(REDRAWNLA, 0);
273                         ob->ctime= -1234567.0f; // eveil! 
274                         DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
275                 }
276         }       
277 }
278
279 static void find_stridechannel(Object *ob, bActionStrip *strip)
280 {
281         if(ob && ob->pose) {
282                 bPoseChannel *pchan;
283                 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next)
284                         if(pchan->flag & POSE_STRIDE)
285                                 break;
286                 if(pchan)
287                         BLI_strncpy(strip->stridechannel, pchan->name, 32);
288                 else
289                         strip->stridechannel[0]= 0;
290         }
291 }
292
293 static void convert_nla(short mval[2])
294 {
295         bActionStrip *strip, *nstrip;
296         Base *base;
297         float x,y;
298         float   ymax, ymin;
299         int sel=0;
300         short event;
301         char str[128];
302         
303         /* Find out what strip we're over */
304         ymax = count_nla_levels() * (NLACHANNELSKIP+NLACHANNELHEIGHT);
305         ymax+= NLACHANNELHEIGHT/2;
306         
307         areamouseco_to_ipoco(G.v2d, mval, &x, &y);
308         
309         for (base=G.scene->base.first; base; base=base->next){
310                 if (nla_filter(base)) {
311                         
312                         /* Area that encloses object name (or ipo) */
313                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
314                         ymax=ymin;
315                         
316                         /* Check action ipo */
317                         if (base->object->action) {
318                                 ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
319                                 if (y>=ymin && y<=ymax)
320                                         break;
321                                 ymax=ymin;
322                         }                       
323                                 
324                         /* Check nlastrips */
325                         for (strip=base->object->nlastrips.first; strip; strip=strip->next){
326                                 ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
327                                 if (y>=ymin && y<=ymax){
328                                         sel = 1;
329                                         break;
330                                 }
331                                 ymax=ymin;
332                         }
333                         if (sel)
334                                 break;
335                 }
336         }
337         
338         if (base==0 || base->object->action==NULL)
339                 return;
340         
341         sprintf(str, "Convert Action%%t|%s to NLA Strip%%x1", base->object->action->id.name+2);
342         event = pupmenu(str);
343         
344         switch (event){
345         case 1:
346                 if (base->object->action){
347                         /* Make new actionstrip */
348                         nstrip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
349                         
350                         deselect_nlachannel_keys(0);
351                         
352                         /* Link the action to the nstrip */
353                         nstrip->act = base->object->action;
354                         id_us_plus(&nstrip->act->id);
355                         calc_action_range(nstrip->act, &nstrip->actstart, &nstrip->actend);
356                         nstrip->start = nstrip->actstart;
357                         nstrip->end = nstrip->actend;
358                         nstrip->flag = ACTSTRIP_SELECT|ACTSTRIP_LOCK_ACTION;
359                         
360                         find_stridechannel(base->object, nstrip);
361                         set_active_strip(base->object, nstrip);
362                         
363                         nstrip->repeat = 1.0;
364                                                         
365                         BLI_addtail(&base->object->nlastrips, nstrip);
366                         
367                         BIF_undo_push("Convert NLA");
368                         allqueue (REDRAWNLA, 0);
369                 }
370                 
371                 
372                 break;
373         default:
374                 break;
375         }
376 }
377
378 static void add_nla_block(short event)
379 {
380         Object *ob= OBACT;
381         bAction *act=NULL;
382         bActionStrip *strip;
383         int             cur;
384
385         if (event!=-1){
386                 for (cur = 1, act=G.main->action.first; act; act=act->id.next, cur++){
387                         if (cur==event){
388                                 break;
389                         }
390                 }
391         }
392         
393         /* Bail out if no action was chosen */
394         if (!act){
395                 return;
396         }
397         
398         /* Initialize the new action block */
399         strip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
400         
401         deselect_nlachannel_keys(0);
402         
403         /* Link the action to the strip */
404         strip->act = act;
405         id_us_plus(&act->id);
406         calc_action_range(strip->act, &strip->actstart, &strip->actend);
407         strip->start = G.scene->r.cfra;         /* could be mval[0] another time... */
408         strip->end = strip->start + (strip->actend-strip->actstart);
409                 /* simple prevention of zero strips */
410         if(strip->start>strip->end-2) 
411                 strip->end= strip->start+100;
412         strip->repeat = 1.0;
413         
414         strip->flag = ACTSTRIP_SELECT|ACTSTRIP_LOCK_ACTION;
415         
416         find_stridechannel(ob, strip);
417         set_active_strip(ob, strip);
418         strip->object= group_get_member_with_action(ob->dup_group, act);
419         if(strip->object)
420                 id_lib_extern(&strip->object->id);      /* checks lib data, sets correct flag for saving then */
421
422         BLI_addtail(&ob->nlastrips, strip);
423
424         BIF_undo_push("Add NLA strip");
425 }
426
427 static void add_nla_databrowse_callback(unsigned short val)
428 {
429         /* val is not used, databrowse needs it to optional pass an event */
430         short event;
431         
432         if(OBACT==NULL) return;
433         
434         event= G.snla->menunr;  /* set by databrowse or pupmenu */
435         
436         add_nla_block(event);
437 }
438
439 /* Adds strip to to active Object */
440 static void add_nlablock(void)
441 {
442         Object *ob= OBACT;
443         short event;
444         short nr=0;
445         char *str, title[64];
446         
447         if(ob==NULL) {
448                 error("Need active Object to add NLA strips");
449                 return;
450         }
451         
452         sprintf(title, "Add Action strip to: %s", ob->id.name+2);
453         
454         /* Popup action menu */
455         IDnames_to_pupstring(&str, title, NULL, &G.main->action, (ID *)G.scene, &nr);
456         
457         if(nr==-2) {
458                 MEM_freeN(str);
459
460                 activate_databrowse((ID *)NULL, ID_AC, 0, 0, &G.snla->menunr, 
461                                                         add_nla_databrowse_callback );
462                 
463                 return;                 
464         }
465         else {
466                 event = pupmenu_col(str, 20);
467                 MEM_freeN(str);
468                 add_nla_block(event);
469         }
470 }
471
472 /* Adds strip to to active Object */
473 static void relink_active_strip(void)
474 {
475         Object *ob= OBACT;
476         bActionStrip *strip;
477         bAction *act;
478         short event;
479         short cur;
480         char *str;
481         
482         if(ob==NULL) return;
483         
484         for (strip = ob->nlastrips.first; strip; strip=strip->next)
485                 if(strip->flag & ACTSTRIP_ACTIVE)
486                         break;
487         
488         if(strip==NULL) return;
489         
490         /* Popup action menu */
491         IDnames_to_pupstring(&str, "Relink Action strip", NULL, &G.main->action, (ID *)G.scene, NULL);
492         if(str) {
493                 event = pupmenu_col(str, 20);
494                 MEM_freeN(str);
495                 
496                 for (cur = 1, act=G.main->action.first; act; act=act->id.next, cur++){
497                         if (cur==event){
498                                 break;
499                         }
500                 }
501                 
502                 if(act) {
503                         if(strip->act) strip->act->id.us--;
504                         strip->act = act;
505                         id_us_plus(&act->id);
506                         
507                         allqueue(REDRAWVIEW3D, 0);
508                         allqueue(REDRAWACTION, 0);
509                         allqueue(REDRAWNLA, 0);
510                 }
511         }
512 }
513
514
515
516 /* Left hand side of channels display, selects objects */
517 static void mouse_nlachannels(short mval[2])
518 {
519         bActionStrip *strip= NULL;
520         Base    *base;
521         Object *ob=NULL;
522         float   x,y;
523         int             click, obclick=0, actclick=0;
524         int             wsize;
525         
526         wsize = (count_nla_levels ()*(NLACHANNELHEIGHT+NLACHANNELSKIP));
527         wsize+= NLACHANNELHEIGHT/2;
528
529         areamouseco_to_ipoco(G.v2d, mval, &x, &y);
530         click = (int)floor( ((float)wsize - y) / (NLACHANNELHEIGHT+NLACHANNELSKIP));
531         
532         if (click<0)
533                 return;
534
535         for (base = G.scene->base.first; base; base=base->next){
536                 if (nla_filter(base)) {
537                         ob= base->object;
538                         
539                         /* See if this is a base selected */
540                         if (click==0) {
541                                 obclick= 1;
542                                 break;
543                         }
544                         click--;
545                         
546                         /* See if this is an action */
547                         if (ob->action){
548                                 if (click==0) {
549                                         actclick= 1;
550                                         break;
551                                 }
552                                 click--;
553                         }
554
555                         /* See if this is an nla strip */
556                         if(ob->nlastrips.first) {
557                                 for (strip = ob->nlastrips.first; strip; strip=strip->next){
558                                         if (click==0) break;
559                                         click--;                                
560                                 }
561                                 if (strip && click==0) break;
562                         }
563                 }
564         }
565
566         if (!base)
567                 return;
568
569         /* Handle object strip selection */
570         if (G.qual & LR_SHIFTKEY) {
571                 if (base->flag & SELECT) base->flag &= ~SELECT;
572                 else base->flag |= SELECT;
573         }
574         else {
575                 deselect_nlachannels (0);       // Auto clear
576                 base->flag |= SELECT;
577         }
578         ob->flag= base->flag;
579         
580         if(base!=BASACT) set_active_base(base);
581         
582         if(actclick) /* de-activate all strips */
583                 set_active_strip(ob, NULL);
584         else if(strip) /* set action */
585                 set_active_strip(ob, strip);
586
587         /* override option for NLA */
588         if(obclick && mval[0]<25)
589                 ob->nlaflag ^= OB_NLA_OVERRIDE;
590         
591         ob->ctime= -1234567.0f; // eveil! 
592         DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
593
594         allqueue(REDRAWIPO, 0);
595         allqueue(REDRAWVIEW3D, 0);
596         allqueue(REDRAWACTION, 0);
597         allqueue(REDRAWNLA, 0);
598         
599 }
600
601 void deselect_nlachannel_keys (int test)
602 {
603         Base                    *base;
604         int                             sel=1;
605         bActionChannel  *chan;
606         bActionStrip    *strip;
607         bConstraintChannel *conchan;
608         
609         /* Determine if this is selection or deselection */
610         if (test){
611                 for (base=G.scene->base.first; base && sel; base=base->next){
612                         
613                         /* Test object ipos */
614                         if (is_ipo_key_selected(base->object->ipo)){
615                                 sel = 0;
616                                 break;
617                         }
618                         
619                         /* Test object constraint ipos */
620                         if (sel){
621                                 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
622                                         if (is_ipo_key_selected(conchan->ipo)){
623                                                 sel=0;
624                                                 break;
625                                         }
626                                 }
627                         }
628                         
629                         /* Test action ipos */
630                         if (sel){
631                                 if (base->object->action){
632                                         for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
633                                                 if (is_ipo_key_selected(chan->ipo)){
634                                                         sel=0;
635                                                         break;
636                                                 }
637
638                                                 /* Test action constraints */
639                                                 if (sel){
640                                                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
641                                                                 if (is_ipo_key_selected(conchan->ipo)){
642                                                                         sel=0;
643                                                                         break;
644                                                                 }
645                                                         }
646                                                 }
647                                         }
648                                 }
649                         }
650                         
651                         /* Test NLA strips */
652                         if (sel){
653                                 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
654                                         if (strip->flag & ACTSTRIP_SELECT){
655                                                 sel = 0;
656                                                 break;
657                                         }
658                                 }
659                         }
660                 }
661         }
662         else
663                 sel=0;
664         
665         
666         /* Set the flags */
667         for (base=G.scene->base.first; base; base=base->next){
668                 
669                 /* Set the object ipos */
670                 set_ipo_key_selection(base->object->ipo, sel);
671                 
672                 /* Set the object constraint ipos */
673                 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
674                         set_ipo_key_selection(conchan->ipo, sel);                       
675                 }
676
677                 /* Set the action ipos */
678                 if (base->object->action){
679                         for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
680                                 set_ipo_key_selection(chan->ipo, sel);
681                                 /* Set the action constraint ipos */
682                                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
683                                         set_ipo_key_selection(conchan->ipo, sel);
684                         }
685                 }
686                 
687                 /* Set the nlastrips */
688                 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
689                         if (sel)
690                                 strip->flag |= ACTSTRIP_SELECT;
691                         else
692                                 strip->flag &= ~ACTSTRIP_SELECT;
693                 }
694         }
695 }
696
697 /* very bad call! */
698 static void recalc_all_ipos(void)
699 {
700         Ipo *ipo;
701         IpoCurve *icu;
702         
703         /* Go to each ipo */
704         for (ipo=G.main->ipo.first; ipo; ipo=ipo->id.next){
705                 for (icu = ipo->curve.first; icu; icu=icu->next){
706                         sort_time_ipocurve(icu);
707                         testhandles_ipocurve(icu);
708                 }
709         }
710 }
711
712 void transform_nlachannel_keys(int mode, int dummy)
713 {
714         Base *base;
715         TransVert *tv;
716         bActionChannel *chan;
717         bActionStrip *strip;
718         bConstraintChannel *conchan;
719         float   sval[2], cval[2], lastcval[2];
720         float   fac=0.0F;
721         float   deltax, startx;
722         int i;
723         int             loop=1;
724         int             tvtot=0;
725         int             invert=0, firsttime=1;
726         short   mvals[2], mvalc[2];
727         short   cancel=0;
728         char    str[256];
729
730         /* Ensure that partial selections result in beztriple selections */
731         for (base=G.scene->base.first; base; base=base->next){
732
733                 /* Check object ipos */
734                 i= fullselect_ipo_keys(base->object->ipo);
735                 if(i) base->flag |= BA_HAS_RECALC_OB;
736                 tvtot+=i;
737                 
738                 /* Check object constraint ipos */
739                 for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
740                         tvtot+=fullselect_ipo_keys(conchan->ipo);                       
741                 
742                 /* Check action ipos */
743                 if (base->object->action){
744                         /* exclude if strip is selected too */
745                         for (strip=base->object->nlastrips.first; strip; strip=strip->next){
746                                 if (strip->flag & ACTSTRIP_SELECT)
747                                         if(strip->act==base->object->action)
748                                                 break;
749                         }
750                         if(strip==NULL) {
751                                 
752                                 for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
753                                         i= fullselect_ipo_keys(chan->ipo);
754                                         if(i) base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA;
755                                         tvtot+=i;
756                                         
757                                         /* Check action constraint ipos */
758                                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
759                                                 tvtot+=fullselect_ipo_keys(conchan->ipo);
760                                 }
761                         }               
762                 }
763
764                 /* Check nlastrips */
765                 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
766                         if (strip->flag & ACTSTRIP_SELECT) {
767                                 base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA;
768                                 tvtot+=2;
769                         }
770                 }
771         }
772         
773         /* If nothing is selected, bail out */
774         if (!tvtot)
775                 return;
776         
777         
778         /* Build the transvert structure */
779         tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert");
780         tvtot=0;
781         for (base=G.scene->base.first; base; base=base->next){
782                 /* Manipulate object ipos */
783                 tvtot=add_trans_ipo_keys(base->object->ipo, tv, tvtot);
784
785                 /* Manipulate object constraint ipos */
786                 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
787                         tvtot=add_trans_ipo_keys(conchan->ipo, tv, tvtot);
788
789                 /* Manipulate action ipos */
790                 if (base->object->action){
791                         /* exclude if strip is selected too */
792                         for (strip=base->object->nlastrips.first; strip; strip=strip->next){
793                                 if (strip->flag & ACTSTRIP_SELECT)
794                                         if(strip->act==base->object->action)
795                                                 break;
796                         }
797                         if(strip==NULL) {
798                                 
799                                 for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
800                                         tvtot=add_trans_ipo_keys(chan->ipo, tv, tvtot);
801
802                                         /* Manipulate action constraint ipos */
803                                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
804                                                 tvtot=add_trans_ipo_keys(conchan->ipo, tv, tvtot);
805                                 }
806                         }
807                 }
808
809                 /* Manipulate nlastrips */
810                 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
811                         if (strip->flag & ACTSTRIP_SELECT){
812                                 tv[tvtot+0].val=&strip->start;
813                                 tv[tvtot+1].val=&strip->end;
814                                 
815                                 tv[tvtot+0].oldval = strip->start;
816                                 tv[tvtot+1].oldval = strip->end;
817                                 
818                                 tvtot+=2;
819                         }
820                 }
821         }
822         
823         /* Do the event loop */
824         //      cent[0] = curarea->winx + (G.snla->v2d.hor.xmax)/2;
825         //      cent[1] = curarea->winy + (G.snla->v2d.hor.ymax)/2;
826         
827         //      areamouseco_to_ipoco(cent, &cenf[0], &cenf[1]);
828         
829         getmouseco_areawin (mvals);
830         areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]);
831         
832         startx=sval[0];
833         while (loop) {
834                 /*              Get the input */
835                 /*              If we're cancelling, reset transformations */
836                 /*                      Else calc new transformation */
837                 /*              Perform the transformations */
838                 while (qtest()) {
839                         short val;
840                         unsigned short event= extern_qread(&val);
841                         
842                         if (val) {
843                                 switch (event) {
844                                 case LEFTMOUSE:
845                                 case SPACEKEY:
846                                 case RETKEY:
847                                         loop=0;
848                                         break;
849                                 case XKEY:
850                                         break;
851                                 case ESCKEY:
852                                 case RIGHTMOUSE:
853                                         cancel=1;
854                                         loop=0;
855                                         break;
856                                 default:
857                                         arrows_move_cursor(event);
858                                         break;
859                                 };
860                         }
861                 }
862                 
863                 if (cancel) {
864                         for (i=0; i<tvtot; i++) {
865                                 if (tv[i].loc){
866                                         tv[i].loc[0]=tv[i].oldloc[0];
867                                         tv[i].loc[1]=tv[i].oldloc[1];
868                                 }
869                                 if (tv[i].val)
870                                         tv[i].val[0]=tv[i].oldval;
871                         }
872                 }
873                 else {
874                         getmouseco_areawin (mvalc);
875                         areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]);
876                         
877                         if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
878                                 PIL_sleep_ms(10);
879                         }
880                         else {
881                                 for (i=0; i<tvtot; i++){
882                                         if (tv[i].loc)
883                                                 tv[i].loc[0]=tv[i].oldloc[0];
884                                         if (tv[i].val)
885                                                 tv[i].val[0]=tv[i].oldval;
886                                         
887                                         switch (mode){
888                                         case 'g':
889                                                 deltax = cval[0]-sval[0];
890                                                 fac= deltax;
891                                                 
892                                                 apply_keyb_grid(&fac, 0.0F, 1.0F, 0.1F, U.flag & USER_AUTOGRABGRID);
893                                                 
894                                                 if (tv[i].loc)
895                                                         tv[i].loc[0]+=fac;
896                                                 if (tv[i].val)
897                                                         tv[i].val[0]+=fac;
898                                                 break;
899                                         case 's': 
900                                                 startx=mvals[0]-(NLAWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
901                                                 deltax=mvalc[0]-(NLAWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
902                                                 fac= (float)fabs(deltax/startx);
903                                                 
904                                                 apply_keyb_grid(&fac, 0.0F, 0.2F, 0.1F, U.flag & USER_AUTOSIZEGRID);
905                                                 
906                                                 if (invert){
907                                                         if (i % 03 == 0){
908                                                                 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i+2].oldloc));
909                                                         }
910                                                         if (i % 03 == 2){
911                                                                 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i-2].oldloc));
912                                                         }
913                                                         
914                                                         fac*=-1;
915                                                 }
916                                                 startx= (G.scene->r.cfra);
917                                                 
918                                                 if (tv[i].loc){
919                                                         tv[i].loc[0]-= startx;
920                                                         tv[i].loc[0]*=fac;
921                                                         tv[i].loc[0]+= startx;
922                                                 }
923                                                 if (tv[i].val){
924                                                         tv[i].val[0]-= startx;
925                                                         tv[i].val[0]*=fac;
926                                                         tv[i].val[0]+= startx;
927                                                 }
928                                                 
929                                                 break;
930                                         }
931                                 }
932                         
933                                 if (mode=='s'){
934                                         sprintf(str, "sizeX: %.3f", fac);
935                                         headerprint(str);
936                                 }
937                                 else if (mode=='g'){
938                                         sprintf(str, "deltaX: %.3f", fac);
939                                         headerprint(str);
940                                 }
941                                 
942                                 if (G.snla->lock) {
943                                         for (base=G.scene->base.first; base; base=base->next){
944                                                 if(base->flag & BA_HAS_RECALC_OB)
945                                                         base->object->recalc |= OB_RECALC_OB;
946                                                 if(base->flag & BA_HAS_RECALC_DATA)
947                                                         base->object->recalc |= OB_RECALC_DATA;
948                                                 
949                                                 if(base->object->recalc) base->object->ctime= -1234567.0f;      // eveil! 
950                                         }
951                                         
952                                         DAG_scene_flush_update(G.scene, screen_view3d_layers());
953                                         
954                                         force_draw_all(0);
955                                 }
956                                 else {
957                                         force_draw(0);
958                                 }
959                         }
960                 }
961                 
962                 lastcval[0]= cval[0];
963                 lastcval[1]= cval[1];
964                 firsttime= 0;
965         }
966         
967         synchronize_action_strips();
968         
969         /* cleanup */
970         for (base=G.scene->base.first; base; base=base->next)
971                 base->flag &= ~(BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA);
972         
973         if(cancel==0) BIF_undo_push("Select all NLA");
974         recalc_all_ipos();      // bad
975         allqueue (REDRAWVIEW3D, 0);
976         allqueue (REDRAWNLA, 0);
977         allqueue (REDRAWIPO, 0);
978         MEM_freeN (tv);
979 }
980
981 void delete_nlachannel_keys(void)
982 {
983         Base *base;
984         bActionChannel *chan;
985         bConstraintChannel *conchan;
986         bActionStrip *strip, *nextstrip;
987         
988         if (!okee("Erase selected strips and/or keys"))
989                 return;
990         
991         for (base = G.scene->base.first; base; base=base->next){
992
993                 /* Delete object ipos */
994                 delete_ipo_keys(base->object->ipo);
995                 
996                 /* Delete object constraint keys */
997                 for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
998                         delete_ipo_keys(conchan->ipo);
999
1000                 /* Delete NLA strips */
1001                 for (strip = base->object->nlastrips.first; strip; strip=nextstrip){
1002                         nextstrip=strip->next;
1003                         if (strip->flag & ACTSTRIP_SELECT){
1004                                 free_actionstrip(strip);
1005                                 BLI_remlink(&base->object->nlastrips, strip);
1006                                 MEM_freeN(strip);
1007                         }
1008                 }
1009                 
1010                 /* Delete action ipos */
1011                 if (base->object->action){
1012                         for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
1013                                 delete_ipo_keys(chan->ipo);
1014                                 /* Delete action constraint keys */
1015                                 for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1016                                         delete_ipo_keys(conchan->ipo);
1017                         }
1018                 }
1019         }
1020         
1021         synchronize_action_strips();
1022         
1023         BIF_undo_push("Delete NLA keys");
1024         recalc_all_ipos();      // bad
1025         allspace(REMAKEIPO,0);
1026         allqueue (REDRAWVIEW3D, 0);
1027         allqueue(REDRAWNLA, 0);
1028         allqueue(REDRAWIPO, 0);
1029 }
1030
1031 void duplicate_nlachannel_keys(void)
1032 {
1033         Base *base;
1034         bActionChannel *chan;
1035         bConstraintChannel *conchan;
1036         bActionStrip *strip, *laststrip;
1037         
1038         /* Find selected items */
1039         for (base = G.scene->base.first; base; base=base->next){
1040                 /* Duplicate object keys */
1041                 duplicate_ipo_keys(base->object->ipo);
1042                 
1043                 /* Duplicate object constraint keys */
1044                 for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
1045                         duplicate_ipo_keys(conchan->ipo);
1046
1047                 /* Duplicate nla strips */
1048                 laststrip = base->object->nlastrips.last;
1049                 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
1050                         if (strip->flag & ACTSTRIP_SELECT){
1051                                 bActionStrip *newstrip;
1052                                 
1053                                 copy_actionstrip(&newstrip, &strip);
1054                                 
1055                                 BLI_addtail(&base->object->nlastrips, newstrip);
1056                                 
1057                                 strip->flag &= ~ACTSTRIP_SELECT;
1058                                 newstrip->flag |= ACTSTRIP_SELECT;
1059                                 set_active_strip(base->object, newstrip);
1060
1061                         }
1062                         if (strip==laststrip)
1063                                 break;
1064                 }
1065                 
1066                 /* Duplicate actionchannel keys */
1067                 if (base->object->action){
1068                         for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
1069                                 duplicate_ipo_keys(chan->ipo);
1070                                 /* Duplicate action constraint keys */
1071                                 for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1072                                         duplicate_ipo_keys(conchan->ipo);
1073                         }
1074                 }
1075         }
1076         
1077         BIF_undo_push("Duplicate NLA");
1078         transform_nlachannel_keys ('g', 0);
1079 }
1080
1081 void borderselect_nla(void)
1082
1083         Base *base;
1084         rcti rect;
1085         rctf rectf;
1086         int  val, selectmode;
1087         short   mval[2];
1088         float   ymin, ymax;
1089         bActionStrip *strip;
1090         bConstraintChannel *conchan;
1091         
1092         if ( (val = get_border (&rect, 3)) ){
1093     if (val == LEFTMOUSE)
1094       selectmode = SELECT_ADD;
1095     else
1096       selectmode = SELECT_SUBTRACT;
1097
1098                 mval[0]= rect.xmin;
1099                 mval[1]= rect.ymin+2;
1100                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1101                 mval[0]= rect.xmax;
1102                 mval[1]= rect.ymax-2;
1103                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1104                 
1105                 ymax = count_nla_levels();
1106                 ymax*= (NLACHANNELHEIGHT+NLACHANNELSKIP);
1107                 ymax+= (NLACHANNELHEIGHT+NLACHANNELSKIP)/2;
1108         
1109                 for (base=G.scene->base.first; base; base=base->next){
1110                         if (nla_filter(base)) {
1111                                 
1112                                 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1113                                 
1114                                 /* Check object ipos */
1115                                 if (base->object->ipo){
1116                                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
1117                                                 borderselect_ipo_key(base->object->ipo, rectf.xmin, rectf.xmax,
1118                                  selectmode);
1119                                 }
1120                                 /* Check object constraint ipos */
1121                                 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
1122                                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
1123                                                 borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax,
1124                                  selectmode);
1125                                 }
1126                                 
1127                                 ymax=ymin;
1128
1129                                 /* Check action ipos */
1130                                 if (base->object->action){
1131                                         bActionChannel *chan;
1132                                         float xmin, xmax;
1133                                         
1134                                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1135                                         
1136                                         /* if action is mapped in NLA, it returns a correction */
1137                                         xmin= get_action_frame(base->object, rectf.xmin);
1138                                         xmax= get_action_frame(base->object, rectf.xmax);
1139                                         
1140                                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1141                                                 for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
1142                                                         borderselect_ipo_key(chan->ipo, xmin, xmax, selectmode);
1143                                                         /* Check action constraint ipos */
1144                                                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1145                                                                 borderselect_ipo_key(conchan->ipo, xmin, xmax, selectmode);
1146                                                 }
1147                                         }
1148
1149                                         ymax=ymin;
1150                                 }       /* End of if action */
1151                                 
1152                                 /* Skip nlastrips */
1153                                 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
1154                                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1155                                         //
1156                                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1157                                                 if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
1158                                                         if (val==1)
1159                                                                 strip->flag |= ACTSTRIP_SELECT;
1160                                                         else
1161                                                                 strip->flag &= ~ACTSTRIP_SELECT;
1162                                                 }
1163                                         }
1164                                         
1165                                         ymax=ymin;
1166                                 }
1167                         }
1168                 }       
1169                 BIF_undo_push("Border select NLA");
1170                 allqueue(REDRAWNLA, 0);
1171                 allqueue(REDRAWACTION, 0);
1172                 allqueue(REDRAWIPO, 0);
1173         }
1174 }
1175
1176 /* right hand side of window, does ipokeys, actionkeys or strips */
1177 static void mouse_nla(int selectmode)
1178 {
1179         Base *base;
1180         bAction *act;
1181         bActionChannel *chan;
1182         bActionStrip *rstrip;
1183         bConstraintChannel *conchan;
1184         float   selx;
1185         short   mval[2];
1186         short sel, isdone=0;
1187         
1188         getmouseco_areawin (mval);
1189         
1190         /* Try object ipo or ob-constraint ipo selection */
1191         base= get_nearest_nlachannel_ob_key(&selx, &sel);
1192         if (base) {
1193                 isdone= 1;
1194                 
1195                 if (selectmode == SELECT_REPLACE){
1196                         deselect_nlachannel_keys(0);
1197                         selectmode = SELECT_ADD;
1198                 }
1199                 
1200                 select_ipo_key(base->object->ipo, selx, selectmode);
1201                 
1202                 /* Try object constraint selection */
1203                 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
1204                         select_ipo_key(conchan->ipo, selx, selectmode);
1205         }
1206         else {
1207                 /* Try action ipo selection */
1208                 act= get_nearest_nlachannel_ac_key(&selx, &sel);
1209                 if (act) {
1210                         isdone= 1;
1211                         
1212                         if (selectmode == SELECT_REPLACE){
1213                                 deselect_nlachannel_keys(0);
1214                                 selectmode = SELECT_ADD;
1215                         }
1216                         
1217                         for (chan=act->chanbase.first; chan; chan=chan->next) {
1218                                 select_ipo_key(chan->ipo, selx, selectmode);
1219                                 /* Try action constraint selection */
1220                                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1221                                         select_ipo_key(conchan->ipo, selx, selectmode);
1222                         }
1223                 }
1224                 else {
1225         
1226                         /* Try nla strip selection */
1227                         base= get_nearest_nlastrip(&rstrip, &sel);
1228                         if (base){
1229                                 isdone= 1;
1230                                 
1231                                 if (!(G.qual & LR_SHIFTKEY)){
1232                                         deselect_nlachannel_keys(0);
1233                                         sel = 0;
1234                                 }
1235                                 
1236                                 if (sel)
1237                                         rstrip->flag &= ~ACTSTRIP_SELECT;
1238                                 else
1239                                         rstrip->flag |= ACTSTRIP_SELECT;
1240                                 
1241                                 set_active_strip(base->object, rstrip);
1242                                 
1243                                 if(base!=BASACT) set_active_base(base);
1244                         }
1245                 }
1246         }
1247         
1248         if(isdone) {
1249                 std_rmouse_transform(transform_nlachannel_keys);
1250                 
1251                 allqueue(REDRAWIPO, 0);
1252                 allqueue(REDRAWVIEW3D, 0);
1253                 allqueue(REDRAWNLA, 0);
1254         }
1255 }
1256
1257 /* This function is currently more complicated than it seems like it should be.
1258 * However, this will be needed once the nla strip timeline is more complex */
1259 static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel)
1260 {
1261         Base *base, *firstbase=NULL;
1262         bActionStrip *strip, *firststrip=NULL, *foundstrip=NULL;
1263         rctf    rectf;
1264         float ymin, ymax;
1265         short mval[2];
1266         short foundsel = 0;
1267
1268         getmouseco_areawin (mval);
1269         
1270         mval[0]-=7;
1271         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1272         
1273         mval[0]+=14;
1274         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1275         
1276         ymax = count_nla_levels();
1277         ymax*=(NLACHANNELHEIGHT + NLACHANNELSKIP);
1278         ymax+= NLACHANNELHEIGHT/2;
1279         
1280         for (base = G.scene->base.first; base; base=base->next){
1281                 if (nla_filter(base)) {
1282                         
1283                         /* Skip object ipos */
1284                         ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
1285
1286                         /* Skip action ipos */
1287                         if (base->object->action)
1288                                 ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
1289                         
1290                         /* the strips */
1291                         for (strip=base->object->nlastrips.first; strip; strip=strip->next){
1292                                 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1293                                 /* Do Ytest */
1294                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1295                                         /* Do XTest */
1296                                         if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
1297                                                 if (!firstbase){
1298                                                         firstbase=base;
1299                                                         firststrip=strip;
1300                                                         *sel = strip->flag & ACTSTRIP_SELECT;
1301                                                 }
1302                                                 
1303                                                 if (strip->flag & ACTSTRIP_SELECT){ 
1304                                                         if (!foundsel){
1305                                                                 foundsel=1;
1306                                                                 foundstrip = strip;
1307                                                         }
1308                                                 }
1309                                                 else if (foundsel && strip != foundstrip){
1310                                                         *rstrip=strip;
1311                                                         *sel = 0;
1312                                                         return base;
1313                                                 }
1314                                         }
1315                                 }
1316                                 ymax=ymin;
1317                         }
1318                 }
1319         }
1320         *rstrip=firststrip;
1321         return firstbase;
1322 }
1323
1324 static Base *get_nearest_nlachannel_ob_key (float *index, short *sel)
1325 {
1326         Base *base;
1327         IpoCurve *icu;
1328         Base *firstbase=NULL;
1329         bConstraintChannel *conchan;
1330         int     foundsel=0;
1331         float firstvertx=-1, foundx=-1;
1332         int i;
1333         short mval[2];
1334         float ymin, ymax;
1335         rctf    rectf;
1336         
1337         *index=0;
1338         
1339         getmouseco_areawin (mval);
1340         
1341         mval[0]-=7;
1342         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1343         
1344         mval[0]+=14;
1345         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1346         
1347         ymax = count_nla_levels();
1348         
1349         ymax*= (NLACHANNELHEIGHT + NLACHANNELSKIP);
1350         ymax+= NLACHANNELHEIGHT/2;
1351         
1352         *sel=0;
1353         
1354         for (base=G.scene->base.first; base; base=base->next){
1355                 if (nla_filter(base)) {
1356                         
1357                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1358                         
1359                         /* Handle object ipo selection */
1360                         if (base->object->ipo){
1361                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1362                                         for (icu=base->object->ipo->curve.first; icu; icu=icu->next){
1363                                                 for (i=0; i<icu->totvert; i++){
1364                                                         if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
1365                                                                 if (!firstbase){
1366                                                                         firstbase=base;
1367                                                                         firstvertx=icu->bezt[i].vec[1][0];
1368                                                                         *sel = icu->bezt[i].f2 & 1;     
1369                                                                 }
1370                                                                 
1371                                                                 if (icu->bezt[i].f2 & 1){ 
1372                                                                         if (!foundsel){
1373                                                                                 foundsel=1;
1374                                                                                 foundx = icu->bezt[i].vec[1][0];
1375                                                                         }
1376                                                                 }
1377                                                                 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
1378                                                                         *index=icu->bezt[i].vec[1][0];
1379                                                                         *sel = 0;
1380                                                                         return base;
1381                                                                 }
1382                                                         }
1383                                                 }
1384                                         }
1385                                 }
1386                         }
1387                         /* Handle object constraint ipos */
1388                         for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
1389                                 if ( !((ymax < rectf.ymin) || (ymin > rectf.ymax)) && conchan->ipo){
1390                                         for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
1391                                                 for (i=0; i<icu->totvert; i++){
1392                                                         if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
1393                                                                 if (!firstbase){
1394                                                                         firstbase=base;
1395                                                                         firstvertx=icu->bezt[i].vec[1][0];
1396                                                                         *sel = icu->bezt[i].f2 & 1;     
1397                                                                 }
1398                                                                 
1399                                                                 if (icu->bezt[i].f2 & 1){ 
1400                                                                         if (!foundsel){
1401                                                                                 foundsel=1;
1402                                                                                 foundx = icu->bezt[i].vec[1][0];
1403                                                                         }
1404                                                                 }
1405                                                                 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
1406                                                                         *index=icu->bezt[i].vec[1][0];
1407                                                                         *sel = 0;
1408                                                                         return base;
1409                                                                 }
1410                                                         }
1411                                                 }
1412                                         }
1413                                 }
1414                         }
1415
1416                         ymax=ymin;
1417                         
1418                         /* Skip action ipos */
1419                         if (base->object->action){
1420                                 ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
1421                         }
1422                         /* Skip nlastrips */
1423                         ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
1424                 }
1425         }       
1426         
1427         *index=firstvertx;
1428         return firstbase;
1429 }
1430
1431 static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel)
1432 {
1433         Base *base;
1434         IpoCurve *icu;
1435         bAction *firstact=NULL;
1436         bActionChannel *chan;
1437         bConstraintChannel *conchan;
1438         rctf    rectf;
1439         float firstvert=-1, foundx=-1;
1440         float ymin, ymax, xmin, xmax;
1441         int i;
1442         int     foundsel=0;
1443         short mval[2];
1444         
1445         *index=0;
1446         
1447         getmouseco_areawin (mval);
1448         
1449         mval[0]-=7;
1450         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1451         
1452         mval[0]+=14;
1453         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1454         
1455         ymax = count_nla_levels();
1456         
1457         ymax*= (NLACHANNELHEIGHT + NLACHANNELSKIP);
1458         ymax+= NLACHANNELHEIGHT/2;
1459         
1460         *sel=0;
1461         
1462         for (base=G.scene->base.first; base; base=base->next){
1463                 /* Handle object ipo selection */
1464                 if (nla_filter(base)) {
1465                         
1466                         /* Skip object ipo and ob-constraint ipo */
1467                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1468                         ymax=ymin;
1469                         
1470                         /* Handle action ipos */
1471                         if (base->object->action){
1472                                 bAction *act= base->object->action;
1473                                 
1474                                 /* if action is mapped in NLA, it returns a correction */
1475                                 xmin= get_action_frame(base->object, rectf.xmin);
1476                                 xmax= get_action_frame(base->object, rectf.xmax);
1477                                 
1478                                 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1479                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1480                                         for (chan=act->chanbase.first; chan; chan=chan->next){
1481                                                 if(chan->ipo) {
1482                                                         for (icu=chan->ipo->curve.first; icu; icu=icu->next){
1483                                                                 for (i=0; i<icu->totvert; i++){
1484                                                                         if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] <= xmax ){
1485                                                                                 if (!firstact){
1486                                                                                         firstact= act;
1487                                                                                         firstvert=icu->bezt[i].vec[1][0];
1488                                                                                         *sel = icu->bezt[i].f2 & 1;     
1489                                                                                 }
1490                                                                                 
1491                                                                                 if (icu->bezt[i].f2 & 1){ 
1492                                                                                         if (!foundsel){
1493                                                                                                 foundsel=1;
1494                                                                                                 foundx = icu->bezt[i].vec[1][0];
1495                                                                                         }
1496                                                                                 }
1497                                                                                 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
1498                                                                                         *index=icu->bezt[i].vec[1][0];
1499                                                                                         *sel = 0;
1500                                                                                         return act;
1501                                                                                 }
1502                                                                         }
1503                                                                 }
1504                                                         }
1505                                                 }
1506                                                 
1507                                                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1508                                                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1509                                                         if ( !((ymax < rectf.ymin) || (ymin > rectf.ymax)) && conchan->ipo){
1510                                                                 for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
1511                                                                         for (i=0; i<icu->totvert; i++){
1512                                                                                 if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] <= xmax ){
1513                                                                                         if (!firstact){
1514                                                                                                 firstact=base->object->action;
1515                                                                                                 firstvert=icu->bezt[i].vec[1][0];
1516                                                                                                 *sel = icu->bezt[i].f2 & 1;     
1517                                                                                         }
1518                                                                                         
1519                                                                                         if (icu->bezt[i].f2 & 1){ 
1520                                                                                                 if (!foundsel){
1521                                                                                                         foundsel=1;
1522                                                                                                         foundx = icu->bezt[i].vec[1][0];
1523                                                                                                 }
1524                                                                                         }
1525                                                                                         else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
1526                                                                                                 *index=icu->bezt[i].vec[1][0];
1527                                                                                                 *sel = 0;
1528                                                                                                 return base->object->action;
1529                                                                                         }
1530                                                                                 }
1531                                                                         }
1532                                                                 }
1533                                                         }
1534                                                         ymax=ymin;
1535                                                 }
1536                                         
1537                                         
1538                                         }
1539                                 }                       
1540                                 ymax=ymin;
1541                         }
1542                         
1543                         /* Skip nlastrips */
1544                         ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
1545                 }
1546         }       
1547         
1548         *index=firstvert;
1549         return firstact;
1550 }
1551
1552 void deselect_nlachannels(int test)
1553 {
1554         Base *base;
1555         int sel = 1;
1556
1557         if (test){
1558                 for (base=G.scene->base.first; base; base=base->next){
1559                         /* Check base flags for previous selection */
1560                         if (base->flag & SELECT){
1561                                 sel=0;
1562                                 break;
1563                         }
1564                 }
1565         }
1566         else
1567                 sel = 0;
1568
1569         /* Select objects */
1570         for (base=G.scene->base.first; base; base=base->next){
1571                 if (sel){
1572                         if (nla_filter(base))
1573                                 base->flag |= SELECT;
1574                 }
1575                 else
1576                         base->flag &= ~SELECT;
1577                 
1578                 base->object->flag= base->flag;
1579         }       
1580 }
1581
1582 static Object *get_object_from_active_strip(void) {
1583
1584         Base *base;
1585         bActionStrip *strip;
1586         
1587         for (base=G.scene->base.first; base; base=base->next) {
1588                 for (strip = base->object->nlastrips.first; 
1589                          strip; strip=strip->next){
1590                         if (strip->flag & ACTSTRIP_SELECT) {
1591                                 return base->object;
1592                         }
1593                 }
1594         }
1595         return NULL;
1596 }
1597
1598
1599 void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
1600 {
1601         unsigned short event= evt->event;
1602         short val= evt->val;
1603         SpaceNla *snla = curarea->spacedata.first;
1604         int doredraw= 0;
1605         short   mval[2];
1606         float dx,dy;
1607         int     cfra;
1608         short mousebut = L_MOUSE;
1609         Object          *ob; //in shift-B / bake
1610         
1611         if (curarea->win==0) return;
1612         if (!snla) return;
1613         
1614         if(val) {
1615                 if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
1616                 
1617                 /* swap mouse buttons based on user preference */
1618                 if (U.flag & USER_LMOUSESELECT) {
1619                         if (event == LEFTMOUSE) {
1620                                 event = RIGHTMOUSE;
1621                                 mousebut = L_MOUSE;
1622                         } else if (event == RIGHTMOUSE) {
1623                                 event = LEFTMOUSE;
1624                                 mousebut = R_MOUSE;
1625                         }
1626                 }
1627                 
1628                 getmouseco_areawin(mval);
1629                 
1630                 switch(event) {
1631                         case UI_BUT_EVENT:
1632                                 do_nlabuts(val); // in drawnla.c
1633                                 break;
1634                                 
1635                         case HOMEKEY:
1636                                 do_nla_buttons(B_NLAHOME);
1637                                 break;
1638                                 
1639                         case EQUALKEY:
1640                         case PAGEUPKEY:
1641                                 shift_nlastrips_up();
1642                                 break;
1643                                 
1644                         case MINUSKEY:
1645                         case PAGEDOWNKEY:
1646                                 shift_nlastrips_down();
1647                                 break;
1648                                 
1649                         case AKEY:
1650                                 if (G.qual & LR_SHIFTKEY){
1651                                         add_nlablock();
1652                                         allqueue (REDRAWNLA, 0);
1653                                         allqueue (REDRAWVIEW3D, 0);
1654                                 }
1655                                 else{
1656                                         if (mval[0]>=NLAWIDTH)
1657                                                 deselect_nlachannel_keys(1);
1658                                         else{
1659                                                 deselect_nlachannels(1);
1660                                                 allqueue (REDRAWVIEW3D, 0);
1661                                         }
1662                                         allqueue (REDRAWNLA, 0);
1663                                         allqueue (REDRAWIPO, 0);
1664                                         BIF_undo_push("(De)select all NLA");
1665                                 }
1666                                 break;
1667                                 
1668                         case BKEY:
1669                           if (G.qual & LR_SHIFTKEY){
1670                             bake_all_to_action();
1671                             allqueue (REDRAWNLA, 0);
1672                             allqueue (REDRAWVIEW3D, 0);
1673                             BIF_undo_push("Bake All To Action");
1674                             ob = get_object_from_active_strip();
1675                             //build_match_caches(ob);
1676                           }
1677                           else
1678                             borderselect_nla();
1679                           break;
1680                                 
1681                         case CKEY:
1682                                 convert_nla(mval);
1683                                 break;
1684                                 
1685                         case DKEY:
1686                                 if (G.qual & LR_SHIFTKEY && mval[0]>=NLAWIDTH){
1687                                         duplicate_nlachannel_keys();
1688                                         update_for_newframe_muted();
1689                                 }
1690                                 break;
1691                                 
1692                         case GKEY:
1693                                 if (mval[0]>=NLAWIDTH)
1694                                         transform_nlachannel_keys ('g', 0);
1695                                 update_for_newframe_muted();
1696                                 break;
1697                                 
1698                         case NKEY:
1699                                 if(G.qual==0) {
1700                                         toggle_blockhandler(curarea, NLA_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);
1701                                         scrarea_queue_winredraw(curarea);
1702                                 }
1703                                 break;
1704                         case LKEY:
1705                                 relink_active_strip();
1706                                 break;
1707                                 
1708                         case SKEY:
1709                                 if(G.qual==LR_ALTKEY) {
1710                                         val= pupmenu("Action Strip Scale%t|Clear Strip Size%x1|Remap Start/End%x2");
1711                                         if(val==1)
1712                                                 reset_action_strips(1);
1713                                         else if(val==2)
1714                                                 reset_action_strips(2);
1715                                 }
1716                                 else if(G.qual & LR_SHIFTKEY) {
1717                                         if(okee("Snap Strips to Frame"))
1718                                                 snap_action_strips();
1719                                 }
1720                                 else {
1721                                         if (mval[0]>=NLAWIDTH)
1722                                                 transform_nlachannel_keys ('s', 0);
1723                                         update_for_newframe_muted();
1724                                 }
1725                                 break;
1726                                 
1727                         case DELKEY:
1728                         case XKEY:
1729                                 if (mval[0]>=NLAWIDTH)
1730                                         delete_nlachannel_keys ();
1731                                 
1732                                 update_for_newframe_muted();
1733                                 break;
1734                                 
1735                                 /* LEFTMOUSE and RIGHTMOUSE event codes can be swapped above,
1736                                 * based on user preference USER_LMOUSESELECT
1737                                 */
1738                         case LEFTMOUSE:
1739                                 if(view2dmove(LEFTMOUSE))
1740                                         break; // only checks for sliders
1741                                 else if (mval[0]>=snla->v2d.mask.xmin) {
1742                                         do {
1743                                                 getmouseco_areawin(mval);
1744                                                 
1745                                                 areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
1746                                                 
1747                                                 cfra= (int)dx;
1748                                                 if(cfra< 1) cfra= 1;
1749                                                 
1750                                                 if( cfra!=CFRA ) {
1751                                                         CFRA= cfra;
1752                                                         update_for_newframe();
1753                                                         force_draw_all(0);
1754                                                 }
1755                                                 else PIL_sleep_ms(30);
1756                                                 
1757                                         } while(get_mbut() & mousebut);
1758                                         break;
1759                                 }
1760                                         /* else pass on! */
1761                                 case RIGHTMOUSE:
1762                                         if (mval[0]>=snla->v2d.mask.xmin) {
1763                                                 if(G.qual & LR_SHIFTKEY)
1764                                                         mouse_nla(SELECT_INVERT);
1765                                                 else
1766                                                         mouse_nla(SELECT_REPLACE);
1767                                         }
1768                                         else
1769                                                 mouse_nlachannels(mval);
1770                                         break;
1771                                         
1772                                 case PADPLUSKEY:
1773                                         view2d_zoom(G.v2d, 0.1154, sa->winx, sa->winy);
1774                                         test_view2d(G.v2d, sa->winx, sa->winy);
1775                                         view2d_do_locks(curarea, V2D_LOCK_COPY);
1776                                         doredraw= 1;
1777                                         break;
1778                                 case PADMINUS:
1779                                         view2d_zoom(G.v2d, -0.15, sa->winx, sa->winy);
1780                                         test_view2d(G.v2d, sa->winx, sa->winy);
1781                                         view2d_do_locks(curarea, V2D_LOCK_COPY);
1782                                         doredraw= 1;
1783                                         break;
1784                                 case MIDDLEMOUSE:
1785                                 case WHEELUPMOUSE:
1786                                 case WHEELDOWNMOUSE:
1787                                         view2dmove(event);      /* in drawipo.c */
1788                                         break;
1789                 }
1790         }
1791         
1792         if(doredraw) scrarea_queue_winredraw(curarea);
1793 }
1794
1795 static void add_nla_block_by_name(char name[32], Object *ob, short hold, short add, float repeat)
1796 {
1797         bAction *act=NULL;
1798         bActionStrip *strip;
1799         int             cur;
1800
1801         if (name){
1802                 for (cur = 1, act=G.main->action.first; act; act=act->id.next, cur++){
1803                         if (strcmp(name,act->id.name)==0) {
1804                                 break;
1805                         }
1806                 }
1807         }
1808         
1809         /* Bail out if no action was chosen */
1810         if (!act){
1811                 return;
1812         }
1813         
1814         /* Initialize the new action block */
1815         strip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
1816         
1817         deselect_nlachannel_keys(0);
1818         
1819         /* Link the action to the strip */
1820         strip->act = act;
1821         calc_action_range(strip->act, &strip->actstart, &strip->actend);
1822         strip->start = G.scene->r.cfra;         /* could be mval[0] another time... */
1823         strip->end = strip->start + (strip->actend-strip->actstart);
1824                 /* simple prevention of zero strips */
1825         if(strip->start>strip->end-2) 
1826                 strip->end= strip->start+100;
1827         
1828         strip->flag = ACTSTRIP_SELECT|ACTSTRIP_LOCK_ACTION; //|ACTSTRIP_USEMATCH;
1829         
1830         if (hold==1)
1831                 strip->flag = strip->flag|ACTSTRIP_HOLDLASTFRAME;
1832                 
1833         if (add==1)
1834                 strip->mode = ACTSTRIPMODE_ADD;
1835         
1836         find_stridechannel(ob, strip);
1837         
1838         set_active_strip(ob, strip);
1839         
1840         strip->repeat = repeat;
1841         
1842         act->id.us++;
1843         
1844         BLI_addtail(&ob->nlastrips, strip);
1845
1846         BIF_undo_push("Add NLA strip");
1847 }
1848
1849 void bake_all_to_action(void)
1850 {
1851         Object          *ob;
1852         bAction         *newAction;
1853         Ipo             *ipo;
1854         ID              *id;
1855         short           hold, add;
1856         float           repeat;
1857
1858         /* burn object-level motion into a new action */
1859         ob = get_object_from_active_strip();
1860         if (ob) {
1861                 if (ob->flag&OB_ARMATURE) {
1862                         newAction = bake_obIPO_to_action(ob);
1863                         if (newAction) {
1864                                 /* unlink the object's IPO */
1865                                 ipo=ob->ipo;
1866                                 if (ipo) {
1867                                         id = &ipo->id;
1868                                         if (id->us > 0)
1869                                                 id->us--;
1870                                         ob->ipo = NULL;
1871                                 }
1872                                 
1873                                 /* add the new Action to NLA as a strip */
1874                                 hold=1;
1875                                 add=1;
1876                                 repeat=1.0;
1877                                 printf("about to add nla block...\n");
1878                                 add_nla_block_by_name(newAction->id.name, ob, hold, add, repeat);
1879                         }
1880                 }
1881         }
1882 }