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