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