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