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