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