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