Another merger of Orange branch with bf-blender, it has important fixes.
[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_depsgraph.h"
58 #include "BKE_group.h"
59 #include "BKE_global.h"
60 #include "BKE_ipo.h"
61 #include "BKE_library.h"
62 #include "BKE_main.h"
63 #include "BKE_nla.h"
64
65 #include "BIF_screen.h"
66 #include "BIF_interface.h"
67 #include "BIF_butspace.h"
68 #include "BIF_space.h"
69 #include "BIF_mywindow.h"
70 #include "BIF_editview.h"
71 #include "BIF_toolbox.h"
72 #include "BIF_editnla.h"
73
74 #include "BSE_editipo.h"
75 #include "BSE_editnla_types.h"
76 #include "BSE_headerbuttons.h"
77 #include "BSE_drawipo.h"
78 #include "BSE_trans_types.h"
79 #include "BSE_edit.h"
80 #include "BSE_filesel.h"
81 #include "BDR_editobject.h"
82 #include "BSE_drawnla.h"
83
84 #include "blendef.h"
85 #include "mydevice.h"
86
87 #ifdef HAVE_CONFIG_H
88 #include <config.h>
89 #endif
90
91 /* Note: A lot of these pretty much duplicate the behaviour of the
92 action windows.  The functions should be shared, not copy-pasted */
93
94 static void mouse_nla(int selectmode);
95 static Base *get_nearest_nlachannel_ob_key (float *index, short *sel);
96 static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel);
97 static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel);
98 static void mouse_nlachannels(short mval[2]);
99 static void convert_nla(short mval[2]);
100
101 /* ******************** SPACE: NLA ********************** */
102
103 void shift_nlastrips_up(void) {
104         
105         Base *base;
106         bActionStrip *strip, *prevstrip;
107
108         for (base=G.scene->base.first; base; base=base->next) {
109                 for (strip = base->object->nlastrips.first; 
110                          strip; strip=strip->next){
111                         if (strip->flag & ACTSTRIP_SELECT) {
112                                 if ( (prevstrip = strip->prev) ) {
113                                         if (prevstrip->prev)
114                                                 prevstrip->prev->next = strip;
115                                         if (strip->next)
116                                                 strip->next->prev = prevstrip;
117                                         strip->prev = prevstrip->prev;
118                                         prevstrip->next = strip->next;
119                                         strip->next = prevstrip;
120                                         prevstrip->prev = strip;
121
122                                         if (prevstrip == base->object->nlastrips.first)
123                                                 base->object->nlastrips.first = strip;
124                                         if (strip == base->object->nlastrips.last)
125                                                 base->object->nlastrips.last = prevstrip;
126
127                                         strip = prevstrip;
128                                 }
129                                 else {
130                                         break;
131                                 }
132                         }
133                 }
134         }
135         BIF_undo_push("Shift NLA strip");
136         allqueue (REDRAWNLA, 0);
137
138 }
139
140 void shift_nlastrips_down(void) {
141         
142         Base *base;
143         bActionStrip *strip, *nextstrip;
144
145         for (base=G.scene->base.first; base; base=base->next) {
146                 for (strip = base->object->nlastrips.last; 
147                          strip; strip=strip->prev){
148                         if (strip->flag & ACTSTRIP_SELECT) {
149                                 if ( (nextstrip = strip->next) ) {
150                                         if (nextstrip->next)
151                                                 nextstrip->next->prev = strip;
152                                         if (strip->prev)
153                                                 strip->prev->next = nextstrip;
154                                         strip->next = nextstrip->next;
155                                         nextstrip->prev = strip->prev;
156                                         strip->prev = nextstrip;
157                                         nextstrip->next = strip;
158
159                                         if (nextstrip == base->object->nlastrips.last)
160                                                 base->object->nlastrips.last = strip;
161                                         if (strip == base->object->nlastrips.first)
162                                                 base->object->nlastrips.first = nextstrip;
163
164                                         strip = nextstrip;
165                                 }
166                                 else {
167                                         break;
168                                 }
169                         }
170                 }
171         }
172         
173         BIF_undo_push("Shift NLA strips");
174         allqueue (REDRAWNLA, 0);
175 }
176
177 void synchronize_action_strips(void)
178 {
179         Base *base;
180         bActionStrip *strip;
181         
182         for (base=G.scene->base.first; base; base=base->next) {
183                 for (strip = base->object->nlastrips.last; strip; strip=strip->prev) {
184                         if (strip->flag & ACTSTRIP_LOCK_ACTION) {
185                                 float actstart, actend;
186                                 
187                                 calc_action_range(strip->act, &actstart, &actend);
188                                 
189                                 if(strip->actstart!=actstart || strip->actend!=actend) {
190                                         float mapping= (strip->end - strip->start)/(strip->actend - strip->actstart);
191                                         
192                                         strip->start+= mapping*(actstart - strip->actstart);
193                                         strip->end+= mapping*(actend - strip->actend);
194                                         
195                                         strip->actstart= actstart;
196                                         strip->actend= actend;
197                                 }
198                         }
199                 }
200         }
201         
202 }
203
204 void reset_action_strips(int val)
205 {
206         Base *base;
207         bActionStrip *strip;
208         
209         for (base=G.scene->base.first; base; base=base->next) {
210                 for (strip = base->object->nlastrips.last; strip; strip=strip->prev) {
211                         if (strip->flag & ACTSTRIP_SELECT) {
212                                 if(val==2) {
213                                         calc_action_range(strip->act, &strip->actstart, &strip->actend);
214                                 }
215                                 else if(val==1) {
216                                         float mapping= (strip->actend - strip->actstart)/(strip->end - strip->start);
217                                         
218                                         strip->end= strip->start + mapping*(strip->end - strip->start);
219                                 }
220                                 base->object->ctime= -1234567.0f;       // eveil! 
221                                 DAG_object_flush_update(G.scene, base->object, OB_RECALC_OB|OB_RECALC_DATA);
222                         }
223                 }
224         }
225         BIF_undo_push("Reset NLA strips");
226         allqueue (REDRAWVIEW3D, 0);
227         allqueue (REDRAWACTION, 0);
228         allqueue (REDRAWNLA, 0);
229 }
230
231 void snap_action_strips(void)
232 {
233         Base *base;
234         bActionStrip *strip;
235         
236         for (base=G.scene->base.first; base; base=base->next) {
237                 for (strip = base->object->nlastrips.last; strip; strip=strip->prev) {
238                         if (strip->flag & ACTSTRIP_SELECT) {
239                                 strip->start= floor(strip->start+0.5);
240                                 strip->end= floor(strip->end+0.5);
241                         }
242                 }
243         }
244         BIF_undo_push("Snap NLA strips");
245         allqueue (REDRAWVIEW3D, 0);
246         allqueue (REDRAWACTION, 0);
247         allqueue (REDRAWNLA, 0);
248 }
249
250 static void set_active_strip(Object *ob, bActionStrip *act)
251 {
252         bActionStrip *strip;
253         
254         for (strip = ob->nlastrips.first; strip; strip=strip->next)
255                 strip->flag &= ~ACTSTRIP_ACTIVE;
256         
257         if(act) {
258                 act->flag |= ACTSTRIP_ACTIVE;
259         
260                 if(ob->action!=act->act) {
261                         if(ob->action) ob->action->id.us--;
262                         if(act->act->id.lib) {
263                                 ob->action= NULL;
264                         }
265                         else {
266                                 ob->action= act->act;
267                                 id_us_plus(&ob->action->id);
268                         }                       
269                         allqueue(REDRAWIPO, 0);
270                         allqueue(REDRAWVIEW3D, 0);
271                         allqueue(REDRAWACTION, 0);
272                         allqueue(REDRAWNLA, 0);
273                         ob->ctime= -1234567.0f; // eveil! 
274                         DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
275                 }
276         }       
277 }
278
279 static void find_stridechannel(Object *ob, bActionStrip *strip)
280 {
281         if(ob && ob->pose) {
282                 bPoseChannel *pchan;
283                 for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next)
284                         if(pchan->flag & POSE_STRIDE)
285                                 break;
286                 if(pchan)
287                         BLI_strncpy(strip->stridechannel, pchan->name, 32);
288                 else
289                         strip->stridechannel[0]= 0;
290         }
291 }
292
293 static void convert_nla(short mval[2])
294 {
295         bActionStrip *strip, *nstrip;
296         Base *base;
297         float x,y;
298         float   ymax, ymin;
299         int sel=0;
300         short event;
301         char str[128];
302         
303         /* Find out what strip we're over */
304         ymax = count_nla_levels() * (NLACHANNELSKIP+NLACHANNELHEIGHT);
305         ymax+= NLACHANNELHEIGHT/2;
306         
307         areamouseco_to_ipoco(G.v2d, mval, &x, &y);
308         
309         for (base=G.scene->base.first; base; base=base->next){
310                 if (nla_filter(base)) {
311                         
312                         /* Area that encloses object name (or ipo) */
313                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
314                         ymax=ymin;
315                         
316                         /* Check action ipo */
317                         if (base->object->action) {
318                                 ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
319                                 if (y>=ymin && y<=ymax)
320                                         break;
321                                 ymax=ymin;
322                         }                       
323                                 
324                         /* Check nlastrips */
325                         for (strip=base->object->nlastrips.first; strip; strip=strip->next){
326                                 ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
327                                 if (y>=ymin && y<=ymax){
328                                         sel = 1;
329                                         break;
330                                 }
331                                 ymax=ymin;
332                         }
333                         if (sel)
334                                 break;
335                 }
336         }
337         
338         if (base==0 || base->object->action==NULL)
339                 return;
340         
341         sprintf(str, "Convert Action%%t|%s to NLA Strip%%x1", base->object->action->id.name+2);
342         event = pupmenu(str);
343         
344         switch (event){
345         case 1:
346                 if (base->object->action){
347                         /* Make new actionstrip */
348                         nstrip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
349                         
350                         deselect_nlachannel_keys(0);
351                         
352                         /* Link the action to the nstrip */
353                         nstrip->act = base->object->action;
354                         nstrip->act->id.us++;
355                         calc_action_range(nstrip->act, &nstrip->actstart, &nstrip->actend);
356                         nstrip->start = nstrip->actstart;
357                         nstrip->end = nstrip->actend;
358                         nstrip->flag = ACTSTRIP_SELECT|ACTSTRIP_LOCK_ACTION;
359                         
360                         find_stridechannel(base->object, nstrip);
361                         set_active_strip(base->object, nstrip);
362                         
363                         nstrip->repeat = 1.0;
364                                                         
365                         BLI_addtail(&base->object->nlastrips, nstrip);
366                         
367                         BIF_undo_push("Convert NLA");
368                         allqueue (REDRAWNLA, 0);
369                 }
370                 
371                 
372                 break;
373         default:
374                 break;
375         }
376 }
377
378 static void add_nla_block(short event)
379 {
380         Object *ob= OBACT;
381         bAction *act=NULL;
382         bActionStrip *strip;
383         int             cur;
384
385         if (event!=-1){
386                 for (cur = 1, act=G.main->action.first; act; act=act->id.next, cur++){
387                         if (cur==event){
388                                 break;
389                         }
390                 }
391         }
392         
393         /* Bail out if no action was chosen */
394         if (!act){
395                 return;
396         }
397         
398         /* Initialize the new action block */
399         strip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
400         
401         deselect_nlachannel_keys(0);
402         
403         /* Link the action to the strip */
404         strip->act = act;
405         id_us_plus(&act->id);
406         calc_action_range(strip->act, &strip->actstart, &strip->actend);
407         strip->start = G.scene->r.cfra;         /* could be mval[0] another time... */
408         strip->end = strip->start + (strip->actend-strip->actstart);
409                 /* simple prevention of zero strips */
410         if(strip->start>strip->end-2) 
411                 strip->end= strip->start+100;
412         strip->repeat = 1.0;
413         
414         strip->flag = ACTSTRIP_SELECT|ACTSTRIP_LOCK_ACTION;
415         
416         find_stridechannel(ob, strip);
417         set_active_strip(ob, strip);
418         strip->object= group_get_member_with_action(ob->dup_group, act);
419         if(strip->object)
420                 id_lib_extern(&strip->object->id);      /* checks lib data, sets correct flag for saving then */
421
422         BLI_addtail(&ob->nlastrips, strip);
423
424         BIF_undo_push("Add NLA strip");
425 }
426
427 static void add_nla_databrowse_callback(unsigned short val)
428 {
429         /* val is not used, databrowse needs it to optional pass an event */
430         short event;
431         
432         if(OBACT==NULL) return;
433         
434         event= G.snla->menunr;  /* set by databrowse or pupmenu */
435         
436         add_nla_block(event);
437 }
438
439 /* Adds strip to to active Object */
440 static void add_nlablock(void)
441 {
442         Object *ob= OBACT;
443         short event;
444         short nr=0;
445         char *str;
446         
447         if(ob==NULL) {
448                 error("Need active Object to add NLA strips");
449                 return;
450         }
451         
452         /* Popup action menu */
453         IDnames_to_pupstring(&str, "Add Action strip", NULL, &G.main->action, (ID *)G.scene, &nr);
454         
455         if(nr==-2) {
456                 MEM_freeN(str);
457
458                 activate_databrowse((ID *)NULL, ID_AC, 0, 0, &G.snla->menunr, 
459                                                         add_nla_databrowse_callback );
460                 
461                 return;                 
462         }
463         else {
464                 event = pupmenu_col(str, 20);
465                 MEM_freeN(str);
466                 add_nla_block(event);
467         }
468 }
469
470 /* Adds strip to to active Object */
471 static void relink_active_strip(void)
472 {
473         Object *ob= OBACT;
474         bActionStrip *strip;
475         bAction *act;
476         short event;
477         short cur;
478         char *str;
479         
480         if(ob==NULL) return;
481         
482         for (strip = ob->nlastrips.first; strip; strip=strip->next)
483                 if(strip->flag & ACTSTRIP_ACTIVE)
484                         break;
485         
486         if(strip==NULL) return;
487         
488         /* Popup action menu */
489         IDnames_to_pupstring(&str, "Relink Action strip", NULL, &G.main->action, (ID *)G.scene, NULL);
490         if(str) {
491                 event = pupmenu_col(str, 20);
492                 MEM_freeN(str);
493                 
494                 for (cur = 1, act=G.main->action.first; act; act=act->id.next, cur++){
495                         if (cur==event){
496                                 break;
497                         }
498                 }
499                 
500                 if(act) {
501                         if(strip->act) strip->act->id.us--;
502                         strip->act = act;
503                         id_us_plus(&act->id);
504                         
505                         allqueue(REDRAWVIEW3D, 0);
506                         allqueue(REDRAWACTION, 0);
507                         allqueue(REDRAWNLA, 0);
508                 }
509         }
510 }
511
512
513
514 /* Left hand side of channels display, selects objects */
515 static void mouse_nlachannels(short mval[2])
516 {
517         bActionStrip *strip= NULL;
518         Base    *base;
519         Object *ob=NULL;
520         float   x,y;
521         int             click, obclick=0, actclick=0;
522         int             wsize;
523         
524         wsize = (count_nla_levels ()*(NLACHANNELHEIGHT+NLACHANNELSKIP));
525         wsize+= NLACHANNELHEIGHT/2;
526
527         areamouseco_to_ipoco(G.v2d, mval, &x, &y);
528         click = (int)floor( ((float)wsize - y) / (NLACHANNELHEIGHT+NLACHANNELSKIP));
529         
530         if (click<0)
531                 return;
532
533         for (base = G.scene->base.first; base; base=base->next){
534                 if (nla_filter(base)) {
535                         ob= base->object;
536                         
537                         /* See if this is a base selected */
538                         if (click==0) {
539                                 obclick= 1;
540                                 break;
541                         }
542                         click--;
543                         
544                         /* See if this is an action */
545                         if (ob->action){
546                                 if (click==0) {
547                                         actclick= 1;
548                                         break;
549                                 }
550                                 click--;
551                         }
552
553                         /* See if this is an nla strip */
554                         if(ob->nlastrips.first) {
555                                 for (strip = ob->nlastrips.first; strip; strip=strip->next){
556                                         if (click==0) break;
557                                         click--;                                
558                                 }
559                                 if (strip && click==0) break;
560                         }
561                 }
562         }
563
564         if (!base)
565                 return;
566
567         /* Handle object strip selection */
568         if (G.qual & LR_SHIFTKEY) {
569                 if (base->flag & SELECT) base->flag &= ~SELECT;
570                 else base->flag |= SELECT;
571         }
572         else {
573                 deselect_nlachannels (0);       // Auto clear
574                 base->flag |= SELECT;
575         }
576         ob->flag= base->flag;
577         
578         if(base!=BASACT) set_active_base(base);
579         
580         if(actclick) /* de-activate all strips */
581                 set_active_strip(ob, NULL);
582         else if(strip) /* set action */
583                 set_active_strip(ob, strip);
584
585         /* override option for NLA */
586         if(obclick && mval[0]<25)
587                 ob->nlaflag ^= OB_NLA_OVERRIDE;
588         
589         ob->ctime= -1234567.0f; // eveil! 
590         DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
591
592         allqueue(REDRAWIPO, 0);
593         allqueue(REDRAWVIEW3D, 0);
594         allqueue(REDRAWACTION, 0);
595         allqueue(REDRAWNLA, 0);
596         
597 }
598
599 void deselect_nlachannel_keys (int test)
600 {
601         Base                    *base;
602         int                             sel=1;
603         bActionChannel  *chan;
604         bActionStrip    *strip;
605         bConstraintChannel *conchan;
606         
607         /* Determine if this is selection or deselection */
608         if (test){
609                 for (base=G.scene->base.first; base && sel; base=base->next){
610                         
611                         /* Test object ipos */
612                         if (is_ipo_key_selected(base->object->ipo)){
613                                 sel = 0;
614                                 break;
615                         }
616                         
617                         /* Test object constraint ipos */
618                         if (sel){
619                                 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
620                                         if (is_ipo_key_selected(conchan->ipo)){
621                                                 sel=0;
622                                                 break;
623                                         }
624                                 }
625                         }
626                         
627                         /* Test action ipos */
628                         if (sel){
629                                 if (base->object->action){
630                                         for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
631                                                 if (is_ipo_key_selected(chan->ipo)){
632                                                         sel=0;
633                                                         break;
634                                                 }
635
636                                                 /* Test action constraints */
637                                                 if (sel){
638                                                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
639                                                                 if (is_ipo_key_selected(conchan->ipo)){
640                                                                         sel=0;
641                                                                         break;
642                                                                 }
643                                                         }
644                                                 }
645                                         }
646                                 }
647                         }
648                         
649                         /* Test NLA strips */
650                         if (sel){
651                                 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
652                                         if (strip->flag & ACTSTRIP_SELECT){
653                                                 sel = 0;
654                                                 break;
655                                         }
656                                 }
657                         }
658                 }
659         }
660         else
661                 sel=0;
662         
663         
664         /* Set the flags */
665         for (base=G.scene->base.first; base; base=base->next){
666                 
667                 /* Set the object ipos */
668                 set_ipo_key_selection(base->object->ipo, sel);
669                 
670                 /* Set the object constraint ipos */
671                 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
672                         set_ipo_key_selection(conchan->ipo, sel);                       
673                 }
674
675                 /* Set the action ipos */
676                 if (base->object->action){
677                         for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
678                                 set_ipo_key_selection(chan->ipo, sel);
679                                 /* Set the action constraint ipos */
680                                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
681                                         set_ipo_key_selection(conchan->ipo, sel);
682                         }
683                 }
684                 
685                 /* Set the nlastrips */
686                 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
687                         if (sel)
688                                 strip->flag |= ACTSTRIP_SELECT;
689                         else
690                                 strip->flag &= ~ACTSTRIP_SELECT;
691                 }
692         }
693 }
694
695 /* very bad call! */
696 static void recalc_all_ipos(void)
697 {
698         Ipo *ipo;
699         IpoCurve *icu;
700         
701         /* Go to each ipo */
702         for (ipo=G.main->ipo.first; ipo; ipo=ipo->id.next){
703                 for (icu = ipo->curve.first; icu; icu=icu->next){
704                         sort_time_ipocurve(icu);
705                         testhandles_ipocurve(icu);
706                 }
707         }
708 }
709
710 void transform_nlachannel_keys(int mode, int dummy)
711 {
712         Base *base;
713         TransVert *tv;
714         bActionChannel *chan;
715         bActionStrip *strip;
716         bConstraintChannel *conchan;
717         float   sval[2], cval[2], lastcval[2];
718         float   fac=0.0F;
719         float   deltax, startx;
720         int i;
721         int             loop=1;
722         int             tvtot=0;
723         int             invert=0, firsttime=1;
724         short   mvals[2], mvalc[2];
725         short   cancel=0;
726         char    str[256];
727
728         /* Ensure that partial selections result in beztriple selections */
729         for (base=G.scene->base.first; base; base=base->next){
730
731                 /* Check object ipos */
732                 i= fullselect_ipo_keys(base->object->ipo);
733                 if(i) base->flag |= BA_HAS_RECALC_OB;
734                 tvtot+=i;
735                 
736                 /* Check object constraint ipos */
737                 for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
738                         tvtot+=fullselect_ipo_keys(conchan->ipo);                       
739                 
740                 /* Check action ipos */
741                 if (base->object->action){
742                         /* exclude if strip is selected too */
743                         for (strip=base->object->nlastrips.first; strip; strip=strip->next){
744                                 if (strip->flag & ACTSTRIP_SELECT)
745                                         if(strip->act==base->object->action)
746                                                 break;
747                         }
748                         if(strip==NULL) {
749                                 
750                                 for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
751                                         i= fullselect_ipo_keys(chan->ipo);
752                                         if(i) base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA;
753                                         tvtot+=i;
754                                         
755                                         /* Check action constraint ipos */
756                                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
757                                                 tvtot+=fullselect_ipo_keys(conchan->ipo);
758                                 }
759                         }               
760                 }
761
762                 /* Check nlastrips */
763                 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
764                         if (strip->flag & ACTSTRIP_SELECT) {
765                                 base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA;
766                                 tvtot+=2;
767                         }
768                 }
769         }
770         
771         /* If nothing is selected, bail out */
772         if (!tvtot)
773                 return;
774         
775         
776         /* Build the transvert structure */
777         tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert");
778         tvtot=0;
779         for (base=G.scene->base.first; base; base=base->next){
780                 /* Manipulate object ipos */
781                 tvtot=add_trans_ipo_keys(base->object->ipo, tv, tvtot);
782
783                 /* Manipulate object constraint ipos */
784                 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
785                         tvtot=add_trans_ipo_keys(conchan->ipo, tv, tvtot);
786
787                 /* Manipulate action ipos */
788                 if (base->object->action){
789                         /* exclude if strip is selected too */
790                         for (strip=base->object->nlastrips.first; strip; strip=strip->next){
791                                 if (strip->flag & ACTSTRIP_SELECT)
792                                         if(strip->act==base->object->action)
793                                                 break;
794                         }
795                         if(strip==NULL) {
796                                 
797                                 for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
798                                         tvtot=add_trans_ipo_keys(chan->ipo, tv, tvtot);
799
800                                         /* Manipulate action constraint ipos */
801                                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
802                                                 tvtot=add_trans_ipo_keys(conchan->ipo, tv, tvtot);
803                                 }
804                         }
805                 }
806
807                 /* Manipulate nlastrips */
808                 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
809                         if (strip->flag & ACTSTRIP_SELECT){
810                                 tv[tvtot+0].val=&strip->start;
811                                 tv[tvtot+1].val=&strip->end;
812                                 
813                                 tv[tvtot+0].oldval = strip->start;
814                                 tv[tvtot+1].oldval = strip->end;
815                                 
816                                 tvtot+=2;
817                         }
818                 }
819         }
820         
821         /* Do the event loop */
822         //      cent[0] = curarea->winx + (G.snla->v2d.hor.xmax)/2;
823         //      cent[1] = curarea->winy + (G.snla->v2d.hor.ymax)/2;
824         
825         //      areamouseco_to_ipoco(cent, &cenf[0], &cenf[1]);
826         
827         getmouseco_areawin (mvals);
828         areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]);
829         
830         startx=sval[0];
831         while (loop) {
832                 /*              Get the input */
833                 /*              If we're cancelling, reset transformations */
834                 /*                      Else calc new transformation */
835                 /*              Perform the transformations */
836                 while (qtest()) {
837                         short val;
838                         unsigned short event= extern_qread(&val);
839                         
840                         if (val) {
841                                 switch (event) {
842                                 case LEFTMOUSE:
843                                 case SPACEKEY:
844                                 case RETKEY:
845                                         loop=0;
846                                         break;
847                                 case XKEY:
848                                         break;
849                                 case ESCKEY:
850                                 case RIGHTMOUSE:
851                                         cancel=1;
852                                         loop=0;
853                                         break;
854                                 default:
855                                         arrows_move_cursor(event);
856                                         break;
857                                 };
858                         }
859                 }
860                 
861                 if (cancel) {
862                         for (i=0; i<tvtot; i++) {
863                                 if (tv[i].loc){
864                                         tv[i].loc[0]=tv[i].oldloc[0];
865                                         tv[i].loc[1]=tv[i].oldloc[1];
866                                 }
867                                 if (tv[i].val)
868                                         tv[i].val[0]=tv[i].oldval;
869                         }
870                 }
871                 else {
872                         getmouseco_areawin (mvalc);
873                         areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]);
874                         
875                         if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
876                                 PIL_sleep_ms(10);
877                         }
878                         else {
879                                 for (i=0; i<tvtot; i++){
880                                         if (tv[i].loc)
881                                                 tv[i].loc[0]=tv[i].oldloc[0];
882                                         if (tv[i].val)
883                                                 tv[i].val[0]=tv[i].oldval;
884                                         
885                                         switch (mode){
886                                         case 'g':
887                                                 deltax = cval[0]-sval[0];
888                                                 fac= deltax;
889                                                 
890                                                 apply_keyb_grid(&fac, 0.0F, 1.0F, 0.1F, U.flag & USER_AUTOGRABGRID);
891                                                 
892                                                 if (tv[i].loc)
893                                                         tv[i].loc[0]+=fac;
894                                                 if (tv[i].val)
895                                                         tv[i].val[0]+=fac;
896                                                 break;
897                                         case 's': 
898                                                 startx=mvals[0]-(NLAWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
899                                                 deltax=mvalc[0]-(NLAWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
900                                                 fac= (float)fabs(deltax/startx);
901                                                 
902                                                 apply_keyb_grid(&fac, 0.0F, 0.2F, 0.1F, U.flag & USER_AUTOSIZEGRID);
903                                                 
904                                                 if (invert){
905                                                         if (i % 03 == 0){
906                                                                 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i+2].oldloc));
907                                                         }
908                                                         if (i % 03 == 2){
909                                                                 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i-2].oldloc));
910                                                         }
911                                                         
912                                                         fac*=-1;
913                                                 }
914                                                 startx= (G.scene->r.cfra);
915                                                 
916                                                 if (tv[i].loc){
917                                                         tv[i].loc[0]-= startx;
918                                                         tv[i].loc[0]*=fac;
919                                                         tv[i].loc[0]+= startx;
920                                                 }
921                                                 if (tv[i].val){
922                                                         tv[i].val[0]-= startx;
923                                                         tv[i].val[0]*=fac;
924                                                         tv[i].val[0]+= startx;
925                                                 }
926                                                 
927                                                 break;
928                                         }
929                                 }
930                         
931                                 if (mode=='s'){
932                                         sprintf(str, "sizeX: %.3f", fac);
933                                         headerprint(str);
934                                 }
935                                 else if (mode=='g'){
936                                         sprintf(str, "deltaX: %.3f", fac);
937                                         headerprint(str);
938                                 }
939                                 
940                                 if (G.snla->lock) {
941                                         for (base=G.scene->base.first; base; base=base->next){
942                                                 if(base->flag & BA_HAS_RECALC_OB)
943                                                         base->object->recalc |= OB_RECALC_OB;
944                                                 if(base->flag & BA_HAS_RECALC_DATA)
945                                                         base->object->recalc |= OB_RECALC_DATA;
946                                                 
947                                                 if(base->object->recalc) base->object->ctime= -1234567.0f;      // eveil! 
948                                         }
949                                         
950                                         DAG_scene_flush_update(G.scene, screen_view3d_layers());
951                                         
952                                         force_draw_all(0);
953                                 }
954                                 else {
955                                         force_draw(0);
956                                 }
957                         }
958                 }
959                 
960                 lastcval[0]= cval[0];
961                 lastcval[1]= cval[1];
962                 firsttime= 0;
963         }
964         
965         synchronize_action_strips();
966         
967         /* cleanup */
968         for (base=G.scene->base.first; base; base=base->next)
969                 base->flag &= ~(BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA);
970         
971         if(cancel==0) BIF_undo_push("Select all NLA");
972         recalc_all_ipos();      // bad
973         allqueue (REDRAWVIEW3D, 0);
974         allqueue (REDRAWNLA, 0);
975         allqueue (REDRAWIPO, 0);
976         MEM_freeN (tv);
977 }
978
979 void delete_nlachannel_keys(void)
980 {
981         Base *base;
982         bActionChannel *chan;
983         bConstraintChannel *conchan;
984         bActionStrip *strip, *nextstrip;
985         
986         if (!okee("Erase selected strips and/or keys"))
987                 return;
988         
989         for (base = G.scene->base.first; base; base=base->next){
990
991                 /* Delete object ipos */
992                 delete_ipo_keys(base->object->ipo);
993                 
994                 /* Delete object constraint keys */
995                 for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
996                         delete_ipo_keys(conchan->ipo);
997
998                 /* Delete NLA strips */
999                 for (strip = base->object->nlastrips.first; strip; strip=nextstrip){
1000                         nextstrip=strip->next;
1001                         if (strip->flag & ACTSTRIP_SELECT){
1002                                 free_actionstrip(strip);
1003                                 BLI_remlink(&base->object->nlastrips, strip);
1004                                 MEM_freeN(strip);
1005                         }
1006                 }
1007                 
1008                 /* Delete action ipos */
1009                 if (base->object->action){
1010                         for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
1011                                 delete_ipo_keys(chan->ipo);
1012                                 /* Delete action constraint keys */
1013                                 for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1014                                         delete_ipo_keys(conchan->ipo);
1015                         }
1016                 }
1017         }
1018         
1019         synchronize_action_strips();
1020         
1021         BIF_undo_push("Delete NLA keys");
1022         recalc_all_ipos();      // bad
1023         allspace(REMAKEIPO,0);
1024         allqueue (REDRAWVIEW3D, 0);
1025         allqueue(REDRAWNLA, 0);
1026         allqueue(REDRAWIPO, 0);
1027 }
1028
1029 void duplicate_nlachannel_keys(void)
1030 {
1031         Base *base;
1032         bActionChannel *chan;
1033         bConstraintChannel *conchan;
1034         bActionStrip *strip, *laststrip;
1035         
1036         /* Find selected items */
1037         for (base = G.scene->base.first; base; base=base->next){
1038                 /* Duplicate object keys */
1039                 duplicate_ipo_keys(base->object->ipo);
1040                 
1041                 /* Duplicate object constraint keys */
1042                 for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
1043                         duplicate_ipo_keys(conchan->ipo);
1044
1045                 /* Duplicate nla strips */
1046                 laststrip = base->object->nlastrips.last;
1047                 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
1048                         if (strip->flag & ACTSTRIP_SELECT){
1049                                 bActionStrip *newstrip;
1050                                 
1051                                 copy_actionstrip(&newstrip, &strip);
1052                                 
1053                                 BLI_addtail(&base->object->nlastrips, newstrip);
1054                                 
1055                                 strip->flag &= ~ACTSTRIP_SELECT;
1056                                 newstrip->flag |= ACTSTRIP_SELECT;
1057                                 set_active_strip(base->object, newstrip);
1058
1059                         }
1060                         if (strip==laststrip)
1061                                 break;
1062                 }
1063                 
1064                 /* Duplicate actionchannel keys */
1065                 if (base->object->action){
1066                         for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
1067                                 duplicate_ipo_keys(chan->ipo);
1068                                 /* Duplicate action constraint keys */
1069                                 for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1070                                         duplicate_ipo_keys(conchan->ipo);
1071                         }
1072                 }
1073         }
1074         
1075         BIF_undo_push("Duplicate NLA");
1076         transform_nlachannel_keys ('g', 0);
1077 }
1078
1079 void borderselect_nla(void)
1080
1081         Base *base;
1082         rcti rect;
1083         rctf rectf;
1084         int  val, selectmode;
1085         short   mval[2];
1086         float   ymin, ymax;
1087         bActionStrip *strip;
1088         bConstraintChannel *conchan;
1089         
1090         if ( (val = get_border (&rect, 3)) ){
1091     if (val == LEFTMOUSE)
1092       selectmode = SELECT_ADD;
1093     else
1094       selectmode = SELECT_SUBTRACT;
1095
1096                 mval[0]= rect.xmin;
1097                 mval[1]= rect.ymin+2;
1098                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1099                 mval[0]= rect.xmax;
1100                 mval[1]= rect.ymax-2;
1101                 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1102                 
1103                 ymax = count_nla_levels();
1104                 ymax*= (NLACHANNELHEIGHT+NLACHANNELSKIP);
1105                 ymax+= (NLACHANNELHEIGHT+NLACHANNELSKIP)/2;
1106         
1107                 for (base=G.scene->base.first; base; base=base->next){
1108                         if (nla_filter(base)) {
1109                                 
1110                                 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1111                                 
1112                                 /* Check object ipos */
1113                                 if (base->object->ipo){
1114                                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
1115                                                 borderselect_ipo_key(base->object->ipo, rectf.xmin, rectf.xmax,
1116                                  selectmode);
1117                                 }
1118                                 /* Check object constraint ipos */
1119                                 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
1120                                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
1121                                                 borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax,
1122                                  selectmode);
1123                                 }
1124                                 
1125                                 ymax=ymin;
1126
1127                                 /* Check action ipos */
1128                                 if (base->object->action){
1129                                         bActionChannel *chan;
1130                                         float xmin, xmax;
1131                                         
1132                                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1133                                         
1134                                         /* if action is mapped in NLA, it returns a correction */
1135                                         xmin= get_action_frame(base->object, rectf.xmin);
1136                                         xmax= get_action_frame(base->object, rectf.xmax);
1137                                         
1138                                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1139                                                 for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
1140                                                         borderselect_ipo_key(chan->ipo, xmin, xmax, selectmode);
1141                                                         /* Check action constraint ipos */
1142                                                         for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1143                                                                 borderselect_ipo_key(conchan->ipo, xmin, xmax, selectmode);
1144                                                 }
1145                                         }
1146
1147                                         ymax=ymin;
1148                                 }       /* End of if action */
1149                                 
1150                                 /* Skip nlastrips */
1151                                 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
1152                                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1153                                         //
1154                                         if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1155                                                 if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
1156                                                         if (val==1)
1157                                                                 strip->flag |= ACTSTRIP_SELECT;
1158                                                         else
1159                                                                 strip->flag &= ~ACTSTRIP_SELECT;
1160                                                 }
1161                                         }
1162                                         
1163                                         ymax=ymin;
1164                                 }
1165                         }
1166                 }       
1167                 BIF_undo_push("Border select NLA");
1168                 allqueue(REDRAWNLA, 0);
1169                 allqueue(REDRAWACTION, 0);
1170                 allqueue(REDRAWIPO, 0);
1171         }
1172 }
1173
1174 /* right hand side of window, does ipokeys, actionkeys or strips */
1175 static void mouse_nla(int selectmode)
1176 {
1177         Base *base;
1178         bAction *act;
1179         bActionChannel *chan;
1180         bActionStrip *rstrip;
1181         bConstraintChannel *conchan;
1182         float   selx;
1183         short   mval[2];
1184         short sel, isdone=0;
1185         
1186         getmouseco_areawin (mval);
1187         
1188         /* Try object ipo or ob-constraint ipo selection */
1189         base= get_nearest_nlachannel_ob_key(&selx, &sel);
1190         if (base) {
1191                 isdone= 1;
1192                 
1193                 if (selectmode == SELECT_REPLACE){
1194                         deselect_nlachannel_keys(0);
1195                         selectmode = SELECT_ADD;
1196                 }
1197                 
1198                 select_ipo_key(base->object->ipo, selx, selectmode);
1199                 
1200                 /* Try object constraint selection */
1201                 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
1202                         select_ipo_key(conchan->ipo, selx, selectmode);
1203         }
1204         else {
1205                 /* Try action ipo selection */
1206                 act= get_nearest_nlachannel_ac_key(&selx, &sel);
1207                 if (act) {
1208                         isdone= 1;
1209                         
1210                         if (selectmode == SELECT_REPLACE){
1211                                 deselect_nlachannel_keys(0);
1212                                 selectmode = SELECT_ADD;
1213                         }
1214                         
1215                         for (chan=act->chanbase.first; chan; chan=chan->next) {
1216                                 select_ipo_key(chan->ipo, selx, selectmode);
1217                                 /* Try action constraint selection */
1218                                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1219                                         select_ipo_key(conchan->ipo, selx, selectmode);
1220                         }
1221                 }
1222                 else {
1223         
1224                         /* Try nla strip selection */
1225                         base= get_nearest_nlastrip(&rstrip, &sel);
1226                         if (base){
1227                                 isdone= 1;
1228                                 
1229                                 if (!(G.qual & LR_SHIFTKEY)){
1230                                         deselect_nlachannel_keys(0);
1231                                         sel = 0;
1232                                 }
1233                                 
1234                                 if (sel)
1235                                         rstrip->flag &= ~ACTSTRIP_SELECT;
1236                                 else
1237                                         rstrip->flag |= ACTSTRIP_SELECT;
1238                                 
1239                                 set_active_strip(base->object, rstrip);
1240                                 
1241                                 if(base!=BASACT) set_active_base(base);
1242                         }
1243                 }
1244         }
1245         
1246         if(isdone) {
1247                 std_rmouse_transform(transform_nlachannel_keys);
1248                 
1249                 allqueue(REDRAWIPO, 0);
1250                 allqueue(REDRAWVIEW3D, 0);
1251                 allqueue(REDRAWNLA, 0);
1252         }
1253 }
1254
1255 /* This function is currently more complicated than it seems like it should be.
1256 * However, this will be needed once the nla strip timeline is more complex */
1257 static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel)
1258 {
1259         Base *base, *firstbase=NULL;
1260         bActionStrip *strip, *firststrip=NULL, *foundstrip=NULL;
1261         rctf    rectf;
1262         float ymin, ymax;
1263         short mval[2];
1264         short foundsel = 0;
1265
1266         getmouseco_areawin (mval);
1267         
1268         mval[0]-=7;
1269         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1270         
1271         mval[0]+=14;
1272         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1273         
1274         ymax = count_nla_levels();
1275         ymax*=(NLACHANNELHEIGHT + NLACHANNELSKIP);
1276         ymax+= NLACHANNELHEIGHT/2;
1277         
1278         for (base = G.scene->base.first; base; base=base->next){
1279                 if (nla_filter(base)) {
1280                         
1281                         /* Skip object ipos */
1282                         ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
1283
1284                         /* Skip action ipos */
1285                         if (base->object->action)
1286                                 ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
1287                         
1288                         /* the strips */
1289                         for (strip=base->object->nlastrips.first; strip; strip=strip->next){
1290                                 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1291                                 /* Do Ytest */
1292                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1293                                         /* Do XTest */
1294                                         if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
1295                                                 if (!firstbase){
1296                                                         firstbase=base;
1297                                                         firststrip=strip;
1298                                                         *sel = strip->flag & ACTSTRIP_SELECT;
1299                                                 }
1300                                                 
1301                                                 if (strip->flag & ACTSTRIP_SELECT){ 
1302                                                         if (!foundsel){
1303                                                                 foundsel=1;
1304                                                                 foundstrip = strip;
1305                                                         }
1306                                                 }
1307                                                 else if (foundsel && strip != foundstrip){
1308                                                         *rstrip=strip;
1309                                                         *sel = 0;
1310                                                         return base;
1311                                                 }
1312                                         }
1313                                 }
1314                                 ymax=ymin;
1315                         }
1316                 }
1317         }
1318         *rstrip=firststrip;
1319         return firstbase;
1320 }
1321
1322 static Base *get_nearest_nlachannel_ob_key (float *index, short *sel)
1323 {
1324         Base *base;
1325         IpoCurve *icu;
1326         Base *firstbase=NULL;
1327         bConstraintChannel *conchan;
1328         int     foundsel=0;
1329         float firstvertx=-1, foundx=-1;
1330         int i;
1331         short mval[2];
1332         float ymin, ymax;
1333         rctf    rectf;
1334         
1335         *index=0;
1336         
1337         getmouseco_areawin (mval);
1338         
1339         mval[0]-=7;
1340         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1341         
1342         mval[0]+=14;
1343         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1344         
1345         ymax = count_nla_levels();
1346         
1347         ymax*= (NLACHANNELHEIGHT + NLACHANNELSKIP);
1348         ymax+= NLACHANNELHEIGHT/2;
1349         
1350         *sel=0;
1351         
1352         for (base=G.scene->base.first; base; base=base->next){
1353                 if (nla_filter(base)) {
1354                         
1355                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1356                         
1357                         /* Handle object ipo selection */
1358                         if (base->object->ipo){
1359                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1360                                         for (icu=base->object->ipo->curve.first; icu; icu=icu->next){
1361                                                 for (i=0; i<icu->totvert; i++){
1362                                                         if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
1363                                                                 if (!firstbase){
1364                                                                         firstbase=base;
1365                                                                         firstvertx=icu->bezt[i].vec[1][0];
1366                                                                         *sel = icu->bezt[i].f2 & 1;     
1367                                                                 }
1368                                                                 
1369                                                                 if (icu->bezt[i].f2 & 1){ 
1370                                                                         if (!foundsel){
1371                                                                                 foundsel=1;
1372                                                                                 foundx = icu->bezt[i].vec[1][0];
1373                                                                         }
1374                                                                 }
1375                                                                 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
1376                                                                         *index=icu->bezt[i].vec[1][0];
1377                                                                         *sel = 0;
1378                                                                         return base;
1379                                                                 }
1380                                                         }
1381                                                 }
1382                                         }
1383                                 }
1384                         }
1385                         /* Handle object constraint ipos */
1386                         for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
1387                                 if ( !((ymax < rectf.ymin) || (ymin > rectf.ymax)) && conchan->ipo){
1388                                         for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
1389                                                 for (i=0; i<icu->totvert; i++){
1390                                                         if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
1391                                                                 if (!firstbase){
1392                                                                         firstbase=base;
1393                                                                         firstvertx=icu->bezt[i].vec[1][0];
1394                                                                         *sel = icu->bezt[i].f2 & 1;     
1395                                                                 }
1396                                                                 
1397                                                                 if (icu->bezt[i].f2 & 1){ 
1398                                                                         if (!foundsel){
1399                                                                                 foundsel=1;
1400                                                                                 foundx = icu->bezt[i].vec[1][0];
1401                                                                         }
1402                                                                 }
1403                                                                 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
1404                                                                         *index=icu->bezt[i].vec[1][0];
1405                                                                         *sel = 0;
1406                                                                         return base;
1407                                                                 }
1408                                                         }
1409                                                 }
1410                                         }
1411                                 }
1412                         }
1413
1414                         ymax=ymin;
1415                         
1416                         /* Skip action ipos */
1417                         if (base->object->action){
1418                                 ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
1419                         }
1420                         /* Skip nlastrips */
1421                         ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
1422                 }
1423         }       
1424         
1425         *index=firstvertx;
1426         return firstbase;
1427 }
1428
1429 static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel)
1430 {
1431         Base *base;
1432         IpoCurve *icu;
1433         bAction *firstact=NULL;
1434         bActionChannel *chan;
1435         bConstraintChannel *conchan;
1436         rctf    rectf;
1437         float firstvert=-1, foundx=-1;
1438         float ymin, ymax, xmin, xmax;
1439         int i;
1440         int     foundsel=0;
1441         short mval[2];
1442         
1443         *index=0;
1444         
1445         getmouseco_areawin (mval);
1446         
1447         mval[0]-=7;
1448         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1449         
1450         mval[0]+=14;
1451         areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1452         
1453         ymax = count_nla_levels();
1454         
1455         ymax*= (NLACHANNELHEIGHT + NLACHANNELSKIP);
1456         ymax+= NLACHANNELHEIGHT/2;
1457         
1458         *sel=0;
1459         
1460         for (base=G.scene->base.first; base; base=base->next){
1461                 /* Handle object ipo selection */
1462                 if (nla_filter(base)) {
1463                         
1464                         /* Skip object ipo and ob-constraint ipo */
1465                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1466                         ymax=ymin;
1467                         
1468                         /* Handle action ipos */
1469                         if (base->object->action){
1470                                 bAction *act= base->object->action;
1471                                 
1472                                 /* if action is mapped in NLA, it returns a correction */
1473                                 xmin= get_action_frame(base->object, rectf.xmin);
1474                                 xmax= get_action_frame(base->object, rectf.xmax);
1475                                 
1476                                 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1477                                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1478                                         for (chan=act->chanbase.first; chan; chan=chan->next){
1479                                                 if(chan->ipo) {
1480                                                         for (icu=chan->ipo->curve.first; icu; icu=icu->next){
1481                                                                 for (i=0; i<icu->totvert; i++){
1482                                                                         if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] <= xmax ){
1483                                                                                 if (!firstact){
1484                                                                                         firstact= act;
1485                                                                                         firstvert=icu->bezt[i].vec[1][0];
1486                                                                                         *sel = icu->bezt[i].f2 & 1;     
1487                                                                                 }
1488                                                                                 
1489                                                                                 if (icu->bezt[i].f2 & 1){ 
1490                                                                                         if (!foundsel){
1491                                                                                                 foundsel=1;
1492                                                                                                 foundx = icu->bezt[i].vec[1][0];
1493                                                                                         }
1494                                                                                 }
1495                                                                                 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
1496                                                                                         *index=icu->bezt[i].vec[1][0];
1497                                                                                         *sel = 0;
1498                                                                                         return act;
1499                                                                                 }
1500                                                                         }
1501                                                                 }
1502                                                         }
1503                                                 }
1504                                                 
1505                                                 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1506                                                         ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1507                                                         if ( !((ymax < rectf.ymin) || (ymin > rectf.ymax)) && conchan->ipo){
1508                                                                 for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
1509                                                                         for (i=0; i<icu->totvert; i++){
1510                                                                                 if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] <= xmax ){
1511                                                                                         if (!firstact){
1512                                                                                                 firstact=base->object->action;
1513                                                                                                 firstvert=icu->bezt[i].vec[1][0];
1514                                                                                                 *sel = icu->bezt[i].f2 & 1;     
1515                                                                                         }
1516                                                                                         
1517                                                                                         if (icu->bezt[i].f2 & 1){ 
1518                                                                                                 if (!foundsel){
1519                                                                                                         foundsel=1;
1520                                                                                                         foundx = icu->bezt[i].vec[1][0];
1521                                                                                                 }
1522                                                                                         }
1523                                                                                         else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
1524                                                                                                 *index=icu->bezt[i].vec[1][0];
1525                                                                                                 *sel = 0;
1526                                                                                                 return base->object->action;
1527                                                                                         }
1528                                                                                 }
1529                                                                         }
1530                                                                 }
1531                                                         }
1532                                                         ymax=ymin;
1533                                                 }
1534                                         
1535                                         
1536                                         }
1537                                 }                       
1538                                 ymax=ymin;
1539                         }
1540                         
1541                         /* Skip nlastrips */
1542                         ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
1543                 }
1544         }       
1545         
1546         *index=firstvert;
1547         return firstact;
1548 }
1549
1550 void deselect_nlachannels(int test)
1551 {
1552         Base *base;
1553         int sel = 1;
1554
1555         if (test){
1556                 for (base=G.scene->base.first; base; base=base->next){
1557                         /* Check base flags for previous selection */
1558                         if (base->flag & SELECT){
1559                                 sel=0;
1560                                 break;
1561                         }
1562                 }
1563         }
1564         else
1565                 sel = 0;
1566
1567         /* Select objects */
1568         for (base=G.scene->base.first; base; base=base->next){
1569                 if (sel){
1570                         if (nla_filter(base))
1571                                 base->flag |= SELECT;
1572                 }
1573                 else
1574                         base->flag &= ~SELECT;
1575                 
1576                 base->object->flag= base->flag;
1577         }       
1578 }
1579
1580 void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
1581 {
1582         unsigned short event= evt->event;
1583         short val= evt->val;
1584         SpaceNla *snla = curarea->spacedata.first;
1585         int doredraw= 0;
1586         short   mval[2];
1587         float dx,dy;
1588         int     cfra;
1589         short mousebut = L_MOUSE;
1590         
1591         if (curarea->win==0) return;
1592         if (!snla) return;
1593         
1594         if(val) {
1595                 if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
1596                 
1597                 /* swap mouse buttons based on user preference */
1598                 if (U.flag & USER_LMOUSESELECT) {
1599                         if (event == LEFTMOUSE) {
1600                                 event = RIGHTMOUSE;
1601                                 mousebut = L_MOUSE;
1602                         } else if (event == RIGHTMOUSE) {
1603                                 event = LEFTMOUSE;
1604                                 mousebut = R_MOUSE;
1605                         }
1606                 }
1607                 
1608                 getmouseco_areawin(mval);
1609                 
1610                 switch(event) {
1611                         case UI_BUT_EVENT:
1612                                 do_nlabuts(val); // in drawnla.c
1613                                 break;
1614                                 
1615                         case HOMEKEY:
1616                                 do_nla_buttons(B_NLAHOME);
1617                                 break;
1618                                 
1619                         case EQUALKEY:
1620                         case PAGEUPKEY:
1621                                 shift_nlastrips_up();
1622                                 break;
1623                                 
1624                         case MINUSKEY:
1625                         case PAGEDOWNKEY:
1626                                 shift_nlastrips_down();
1627                                 break;
1628                                 
1629                         case AKEY:
1630                                 if (G.qual & LR_SHIFTKEY){
1631                                         add_nlablock();
1632                                         allqueue (REDRAWNLA, 0);
1633                                         allqueue (REDRAWVIEW3D, 0);
1634                                 }
1635                                 else{
1636                                         if (mval[0]>=NLAWIDTH)
1637                                                 deselect_nlachannel_keys(1);
1638                                         else{
1639                                                 deselect_nlachannels(1);
1640                                                 allqueue (REDRAWVIEW3D, 0);
1641                                         }
1642                                         allqueue (REDRAWNLA, 0);
1643                                         allqueue (REDRAWIPO, 0);
1644                                         BIF_undo_push("(De)select all NLA");
1645                                 }
1646                                 break;
1647                                 
1648                         case BKEY:
1649                                 borderselect_nla();
1650                                 break;
1651                                 
1652                         case CKEY:
1653                                 convert_nla(mval);
1654                                 break;
1655                                 
1656                         case DKEY:
1657                                 if (G.qual & LR_SHIFTKEY && mval[0]>=NLAWIDTH){
1658                                         duplicate_nlachannel_keys();
1659                                         update_for_newframe_muted();
1660                                 }
1661                                 break;
1662                                 
1663                         case GKEY:
1664                                 if (mval[0]>=NLAWIDTH)
1665                                         transform_nlachannel_keys ('g', 0);
1666                                 update_for_newframe_muted();
1667                                 break;
1668                                 
1669                         case NKEY:
1670                                 if(G.qual==0) {
1671                                         toggle_blockhandler(curarea, NLA_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);
1672                                         scrarea_queue_winredraw(curarea);
1673                                 }
1674                                 break;
1675                         case LKEY:
1676                                 relink_active_strip();
1677                                 break;
1678                                 
1679                         case SKEY:
1680                                 if(G.qual==LR_ALTKEY) {
1681                                         val= pupmenu("Action Strip Scale%t|Clear Strip Size%x1|Remap Start/End%x2");
1682                                         if(val==1)
1683                                                 reset_action_strips(1);
1684                                         else if(val==2)
1685                                                 reset_action_strips(2);
1686                                 }
1687                                 else if(G.qual & LR_SHIFTKEY) {
1688                                         if(okee("Snap Strips to Frame"))
1689                                                 snap_action_strips();
1690                                 }
1691                                 else {
1692                                         if (mval[0]>=NLAWIDTH)
1693                                                 transform_nlachannel_keys ('s', 0);
1694                                         update_for_newframe_muted();
1695                                 }
1696                                 break;
1697                                 
1698                         case DELKEY:
1699                         case XKEY:
1700                                 if (mval[0]>=NLAWIDTH)
1701                                         delete_nlachannel_keys ();
1702                                 
1703                                 update_for_newframe_muted();
1704                                 break;
1705                                 
1706                                 /* LEFTMOUSE and RIGHTMOUSE event codes can be swapped above,
1707                                 * based on user preference USER_LMOUSESELECT
1708                                 */
1709                         case LEFTMOUSE:
1710                                 if(view2dmove(LEFTMOUSE))
1711                                         break; // only checks for sliders
1712                                 else if (mval[0]>=snla->v2d.mask.xmin) {
1713                                         do {
1714                                                 getmouseco_areawin(mval);
1715                                                 
1716                                                 areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
1717                                                 
1718                                                 cfra= (int)dx;
1719                                                 if(cfra< 1) cfra= 1;
1720                                                 
1721                                                 if( cfra!=CFRA ) {
1722                                                         CFRA= cfra;
1723                                                         update_for_newframe();
1724                                                         force_draw_all(0);
1725                                                 }
1726                                                 else PIL_sleep_ms(30);
1727                                                 
1728                                         } while(get_mbut() & mousebut);
1729                                         break;
1730                                 }
1731                                         /* else pass on! */
1732                                 case RIGHTMOUSE:
1733                                         if (mval[0]>=snla->v2d.mask.xmin) {
1734                                                 if(G.qual & LR_SHIFTKEY)
1735                                                         mouse_nla(SELECT_INVERT);
1736                                                 else
1737                                                         mouse_nla(SELECT_REPLACE);
1738                                         }
1739                                         else
1740                                                 mouse_nlachannels(mval);
1741                                         break;
1742                                         
1743                                 case PADPLUSKEY:
1744                                         view2d_zoom(G.v2d, 0.1154, sa->winx, sa->winy);
1745                                         test_view2d(G.v2d, sa->winx, sa->winy);
1746                                         view2d_do_locks(curarea, V2D_LOCK_COPY);
1747                                         doredraw= 1;
1748                                         break;
1749                                 case PADMINUS:
1750                                         view2d_zoom(G.v2d, -0.15, sa->winx, sa->winy);
1751                                         test_view2d(G.v2d, sa->winx, sa->winy);
1752                                         view2d_do_locks(curarea, V2D_LOCK_COPY);
1753                                         doredraw= 1;
1754                                         break;
1755                                 case MIDDLEMOUSE:
1756                                 case WHEELUPMOUSE:
1757                                 case WHEELDOWNMOUSE:
1758                                         view2dmove(event);      /* in drawipo.c */
1759                                         break;
1760                 }
1761         }
1762         
1763         if(doredraw) scrarea_queue_winredraw(curarea);
1764 }
1765