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