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