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