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