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