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