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