4 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
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
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.
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.
23 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24 * All rights reserved.
26 * The Original Code is: all of this file.
28 * Contributor(s): none yet.
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.
34 * Hopefully it can be tidied up at a later date...
43 #include "MEM_guardedalloc.h"
45 #include "BLI_blenlib.h"
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"
58 #include "BKE_action.h"
59 #include "BKE_depsgraph.h"
60 #include "BKE_global.h"
62 #include "BKE_library.h"
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"
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"
81 #include "BSE_filesel.h"
82 #include "BDR_editobject.h"
83 #include "BSE_drawnla.h"
92 /* Note: A lot of these pretty much duplicate the behaviour of the
93 action windows. The functions should be shared, not copy-pasted */
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]);
103 /* ******************** SPACE: NLA ********************** */
105 void shift_nlastrips_up(void) {
108 bActionStrip *strip, *prevstrip;
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) ) {
116 prevstrip->prev->next = strip;
118 strip->next->prev = prevstrip;
119 strip->prev = prevstrip->prev;
120 prevstrip->next = strip->next;
121 strip->next = prevstrip;
122 prevstrip->prev = strip;
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;
137 BIF_undo_push("Shift NLA strip");
138 allqueue (REDRAWNLA, 0);
142 void shift_nlastrips_down(void) {
145 bActionStrip *strip, *nextstrip;
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) ) {
153 nextstrip->next->prev = strip;
155 strip->prev->next = nextstrip;
156 strip->next = nextstrip->next;
157 nextstrip->prev = strip->prev;
158 strip->prev = nextstrip;
159 nextstrip->next = strip;
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;
175 BIF_undo_push("Shift NLA strips");
176 allqueue (REDRAWNLA, 0);
179 void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
181 unsigned short event= evt->event;
183 SpaceNla *snla = curarea->spacedata.first;
188 short mousebut = L_MOUSE;
190 if (curarea->win==0) return;
194 if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
196 /* swap mouse buttons based on user preference */
197 if (U.flag & USER_LMOUSESELECT) {
198 if (event == LEFTMOUSE) {
201 } else if (event == RIGHTMOUSE) {
207 getmouseco_areawin(mval);
211 do_nlabuts(val); // in drawnla.c
215 do_nla_buttons(B_NLAHOME);
220 shift_nlastrips_up();
225 shift_nlastrips_down();
229 if (G.qual & LR_SHIFTKEY){
231 allqueue (REDRAWNLA, 0);
232 allqueue (REDRAWVIEW3D, 0);
235 if (mval[0]>=NLAWIDTH)
236 deselect_nlachannel_keys(1);
238 deselect_nlachannels(1);
239 allqueue (REDRAWVIEW3D, 0);
241 allqueue (REDRAWNLA, 0);
242 allqueue (REDRAWIPO, 0);
243 BIF_undo_push("(De)select all NLA");
256 if (G.qual & LR_SHIFTKEY && mval[0]>=NLAWIDTH){
257 duplicate_nlachannel_keys();
258 update_for_newframe_muted();
263 if (mval[0]>=NLAWIDTH)
264 transform_nlachannel_keys ('g', 0);
265 update_for_newframe_muted();
270 toggle_blockhandler(curarea, NLA_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);
271 scrarea_queue_winredraw(curarea);
276 if (mval[0]>=NLAWIDTH)
277 transform_nlachannel_keys ('s', 0);
278 update_for_newframe_muted();
283 if (mval[0]>=NLAWIDTH)
284 delete_nlachannel_keys ();
286 update_for_newframe_muted();
289 /* LEFTMOUSE and RIGHTMOUSE event codes can be swapped above,
290 * based on user preference USER_LMOUSESELECT
293 if(view2dmove(LEFTMOUSE))
294 break; // only checks for sliders
295 else if (mval[0]>=snla->v2d.mask.xmin) {
297 getmouseco_areawin(mval);
299 areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
306 update_for_newframe();
309 else PIL_sleep_ms(30);
311 } while(get_mbut() & mousebut);
316 if (mval[0]>=snla->v2d.mask.xmin) {
317 if(G.qual & LR_SHIFTKEY)
318 mouse_nla(SELECT_INVERT);
320 mouse_nla(SELECT_REPLACE);
323 mouse_nlachannels(mval);
327 view2d_zoom(G.v2d, 0.1154, sa->winx, sa->winy);
328 test_view2d(G.v2d, sa->winx, sa->winy);
329 view2d_do_locks(curarea, V2D_LOCK_COPY);
333 view2d_zoom(G.v2d, -0.15, sa->winx, sa->winy);
334 test_view2d(G.v2d, sa->winx, sa->winy);
335 view2d_do_locks(curarea, V2D_LOCK_COPY);
341 view2dmove(event); /* in drawipo.c */
346 if(doredraw) scrarea_queue_winredraw(curarea);
349 static void set_active_strip(Object *ob, bActionStrip *act)
353 for (strip = ob->nlastrips.first; strip; strip=strip->next)
354 strip->flag &= ~ACTSTRIP_ACTIVE;
357 act->flag |= ACTSTRIP_ACTIVE;
359 if(ob->action!=act->act) {
360 if(ob->action) ob->action->id.us--;
361 ob->action= act->act;
364 allqueue(REDRAWIPO, 0);
365 allqueue(REDRAWVIEW3D, 0);
366 allqueue(REDRAWACTION, 0);
367 allqueue(REDRAWNLA, 0);
368 ob->ctime= -1234567.0f; // eveil!
369 DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
374 static void convert_nla(short mval[2])
381 bActionStrip *strip, *nstrip;
383 /* Find out what strip we're over */
384 ymax = count_nla_levels() * (NLACHANNELSKIP+NLACHANNELHEIGHT);
385 ymax+= NLACHANNELHEIGHT/2;
387 areamouseco_to_ipoco(G.v2d, mval, &x, &y);
389 for (base=G.scene->base.first; base; base=base->next){
390 if (nla_filter(base)) {
391 /* Check object ipo */
392 ymin= ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
393 if (y>=ymin && y<=ymax)
397 /* Check action ipo */
398 ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
399 if (y>=ymin && y<=ymax)
403 /* Check nlastrips */
404 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
405 ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
406 if (y>=ymin && y<=ymax){
420 event = pupmenu("Convert%t|Action to NLA Strip%x1");
423 if (base->object->action){
424 /* Make new actionstrip */
425 nstrip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
427 deselect_nlachannel_keys(0);
429 /* Link the action to the nstrip */
430 nstrip->act = base->object->action;
431 nstrip->actstart = calc_action_start(base->object->action); /* MAKE THIS THE FIRST FRAME OF THE ACTION */
432 nstrip->actend = calc_action_end(base->object->action);
433 nstrip->start = nstrip->actstart;
434 nstrip->end = nstrip->actend;
435 nstrip->flag = ACTSTRIP_SELECT;
436 set_active_strip(base->object, nstrip);
438 nstrip->repeat = 1.0;
440 BLI_addtail(&base->object->nlastrips, nstrip);
443 base->object->action = NULL;
445 BIF_undo_push("Convert NLA");
446 allqueue (REDRAWNLA, 0);
457 static Base *nla_base=NULL; /* global, bad, bad! put it in nla space later, or recode the 2 functions below (ton) */
459 static void add_nla_block(short event)
466 for (cur = 1, act=G.main->action.first; act; act=act->id.next, cur++){
473 /* Bail out if no action was chosen */
478 /* Initialize the new action block */
479 strip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
481 deselect_nlachannel_keys(0);
483 /* Link the action to the strip */
485 strip->actstart = calc_action_start(act);
486 strip->actend = calc_action_end(act);
487 strip->start = G.scene->r.cfra; /* could be mval[0] another time... */
488 strip->end = strip->start + (strip->actend-strip->actstart);
489 /* simple prevention of zero strips */
490 if(strip->start>strip->end-2)
491 strip->end= strip->start+100;
493 strip->flag = ACTSTRIP_SELECT;
494 set_active_strip(nla_base->object, strip);
500 BLI_addtail(&nla_base->object->nlastrips, strip);
502 BIF_undo_push("Add NLA strip");
505 static void add_nla_databrowse_callback(unsigned short val)
507 /* val is not used, databrowse needs it to optional pass an event */
510 if(nla_base==NULL) return;
512 event= G.snla->menunr; /* set by databrowse or pupmenu */
514 add_nla_block(event);
517 static void add_nlablock(short mval[2])
519 /* Make sure we are over an object with action */
528 areamouseco_to_ipoco(G.v2d, mval, &x, &y);
531 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
534 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
536 ymax = count_nla_levels();
537 ymax*= (NLACHANNELHEIGHT + NLACHANNELSKIP);
538 ymax+= NLACHANNELHEIGHT/2;
540 for (base=G.scene->base.first; base; base=base->next){
541 /* Handle object ipo selection */
542 if (nla_filter(base)) {
544 /* Area that encloses object name (or ipo) */
545 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
547 /* Area that encloses action */
548 if (base->object->action)
549 ymin-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
551 /* Area that encloses nla strips */
552 ymin-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*
553 (BLI_countlist(&base->object->nlastrips));
555 /* Test to see the mouse is in an action area */
556 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
563 /* global... for the call above, because the NLA system seems not to have an 'active strip' stored */
566 /* Make sure we have an action */
568 error ("Object has not an Action");
572 /* Popup action menu */
573 IDnames_to_pupstring(&str, "Add Action", NULL, &G.main->action, (ID *)G.scene, &nr);
575 if(strncmp(str+13, "DataBrow", 8)==0) {
578 activate_databrowse((ID *)NULL, ID_AC, 0, 0, &G.snla->menunr,
579 add_nla_databrowse_callback );
584 event = pupmenu(str);
586 add_nla_block(event);
589 /* Ton: this is a callback for databrowse too
590 Hos: no, I don't think it is
595 /* Left hand side of channels display, selects objects */
596 static void mouse_nlachannels(short mval[2])
598 bActionStrip *strip= NULL;
602 int click, obclick=0;
605 wsize = (count_nla_levels ()*(NLACHANNELHEIGHT+NLACHANNELSKIP));
606 wsize+= NLACHANNELHEIGHT/2;
608 areamouseco_to_ipoco(G.v2d, mval, &x, &y);
609 click = (int)floor( ((float)wsize - y) / (NLACHANNELHEIGHT+NLACHANNELSKIP));
614 for (base = G.scene->base.first; base; base=base->next){
615 if (nla_filter(base)) {
618 /* See if this is a base selected */
625 /* See if this is an action */
631 /* See if this is an nla strip */
632 if(ob->nlastrips.first) {
633 for (strip = ob->nlastrips.first; strip; strip=strip->next){
637 if (strip && click==0) break;
645 /* Handle object strip selection */
646 if (G.qual & LR_SHIFTKEY) {
647 if (base->flag & SELECT) base->flag &= ~SELECT;
648 else base->flag |= SELECT;
651 deselect_nlachannels (0); // Auto clear
652 base->flag |= SELECT;
654 ob->flag= base->flag;
656 if(base!=BASACT) set_active_base(base);
660 set_active_strip(ob, strip);
662 /* override option for NLA */
663 if(obclick && mval[0]<25) {
664 ob->nlaflag ^= OB_NLA_OVERRIDE;
665 ob->ctime= -1234567.0f; // eveil!
666 DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
669 allqueue(REDRAWIPO, 0);
670 allqueue(REDRAWVIEW3D, 0);
671 allqueue(REDRAWACTION, 0);
672 allqueue(REDRAWNLA, 0);
676 void deselect_nlachannel_keys (int test)
680 bActionChannel *chan;
682 bConstraintChannel *conchan;
684 /* Determine if this is selection or deselection */
686 for (base=G.scene->base.first; base && sel; base=base->next){
688 /* Test object ipos */
689 if (is_ipo_key_selected(base->object->ipo)){
694 /* Test object constraint ipos */
696 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
697 if (is_ipo_key_selected(conchan->ipo)){
704 /* Test action ipos */
706 if (base->object->action){
707 for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
708 if (is_ipo_key_selected(chan->ipo)){
713 /* Test action constraints */
715 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
716 if (is_ipo_key_selected(conchan->ipo)){
726 /* Test NLA strips */
728 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
729 if (strip->flag & ACTSTRIP_SELECT){
742 for (base=G.scene->base.first; base; base=base->next){
744 /* Set the object ipos */
745 set_ipo_key_selection(base->object->ipo, sel);
747 /* Set the object constraint ipos */
748 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
749 set_ipo_key_selection(conchan->ipo, sel);
752 /* Set the action ipos */
753 if (base->object->action){
754 for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
755 set_ipo_key_selection(chan->ipo, sel);
756 /* Set the action constraint ipos */
757 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
758 set_ipo_key_selection(conchan->ipo, sel);
762 /* Set the nlastrips */
763 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
765 strip->flag |= ACTSTRIP_SELECT;
767 strip->flag &= ~ACTSTRIP_SELECT;
773 static void recalc_all_ipos(void)
779 for (ipo=G.main->ipo.first; ipo; ipo=ipo->id.next){
780 for (icu = ipo->curve.first; icu; icu=icu->next){
781 sort_time_ipocurve(icu);
782 testhandles_ipocurve(icu);
787 void transform_nlachannel_keys(int mode, int dummy)
792 short mvals[2], mvalc[2];
794 float sval[2], cval[2], lastcval[2];
799 float deltax, startx;
801 int invert=0, firsttime=1;
803 bActionChannel *chan;
805 bConstraintChannel *conchan;
807 /* Ensure that partial selections result in beztriple selections */
808 for (base=G.scene->base.first; base; base=base->next){
810 /* Check object ipos */
811 tvtot+=fullselect_ipo_keys(base->object->ipo);
813 /* Check object constraint ipos */
814 for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
815 tvtot+=fullselect_ipo_keys(conchan->ipo);
817 /* Check action ipos */
818 if (base->object->action){
819 for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
820 tvtot+=fullselect_ipo_keys(chan->ipo);
822 /* Check action constraint ipos */
823 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
824 tvtot+=fullselect_ipo_keys(conchan->ipo);
829 /* Check nlastrips */
830 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
831 if (strip->flag & ACTSTRIP_SELECT)
836 /* If nothing is selected, bail out */
841 /* Build the transvert structure */
842 tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert");
844 for (base=G.scene->base.first; base; base=base->next){
845 /* Manipulate object ipos */
846 tvtot=add_trans_ipo_keys(base->object->ipo, tv, tvtot);
848 /* Manipulate object constraint ipos */
849 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
850 tvtot=add_trans_ipo_keys(conchan->ipo, tv, tvtot);
852 /* Manipulate action ipos */
853 if (base->object->action){
854 for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
855 tvtot=add_trans_ipo_keys(chan->ipo, tv, tvtot);
857 /* Manipulate action constraint ipos */
858 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
859 tvtot=add_trans_ipo_keys(conchan->ipo, tv, tvtot);
863 /* Manipulate nlastrips */
864 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
865 if (strip->flag & ACTSTRIP_SELECT){
866 tv[tvtot+0].val=&strip->start;
867 tv[tvtot+1].val=&strip->end;
869 tv[tvtot+0].oldval = strip->start;
870 tv[tvtot+1].oldval = strip->end;
877 /* Do the event loop */
878 // cent[0] = curarea->winx + (G.snla->v2d.hor.xmax)/2;
879 // cent[1] = curarea->winy + (G.snla->v2d.hor.ymax)/2;
881 // areamouseco_to_ipoco(cent, &cenf[0], &cenf[1]);
883 getmouseco_areawin (mvals);
884 areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]);
889 /* If we're cancelling, reset transformations */
890 /* Else calc new transformation */
891 /* Perform the transformations */
894 unsigned short event= extern_qread(&val);
911 arrows_move_cursor(event);
918 for (i=0; i<tvtot; i++) {
920 tv[i].loc[0]=tv[i].oldloc[0];
921 tv[i].loc[1]=tv[i].oldloc[1];
924 tv[i].val[0]=tv[i].oldval;
928 getmouseco_areawin (mvalc);
929 areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]);
931 if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
935 for (i=0; i<tvtot; i++){
937 tv[i].loc[0]=tv[i].oldloc[0];
939 tv[i].val[0]=tv[i].oldval;
943 deltax = cval[0]-sval[0];
946 apply_keyb_grid(&fac, 0.0F, 1.0F, 0.1F, U.flag & USER_AUTOGRABGRID);
954 startx=mvals[0]-(NLAWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
955 deltax=mvalc[0]-(NLAWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
956 fac= (float)fabs(deltax/startx);
958 apply_keyb_grid(&fac, 0.0F, 0.2F, 0.1F, U.flag & USER_AUTOSIZEGRID);
962 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i+2].oldloc));
965 memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i-2].oldloc));
970 startx= (G.scene->r.cfra);
973 tv[i].loc[0]-= startx;
975 tv[i].loc[0]+= startx;
978 tv[i].val[0]-= startx;
980 tv[i].val[0]+= startx;
989 sprintf(str, "sizeX: %.3f", fac);
993 sprintf(str, "deltaX: %.3f", fac);
998 allqueue (REDRAWVIEW3D, 0);
999 allqueue (REDRAWNLA, 0);
1000 allqueue (REDRAWIPO, 0);
1004 addqueue (curarea->win, REDRAWALL, 0);
1009 lastcval[0]= cval[0];
1010 lastcval[1]= cval[1];
1014 if(cancel==0) BIF_undo_push("Select all NLA");
1015 recalc_all_ipos(); // bad
1016 allqueue (REDRAWVIEW3D, 0);
1017 allqueue (REDRAWNLA, 0);
1018 allqueue (REDRAWIPO, 0);
1022 void delete_nlachannel_keys(void)
1025 bActionChannel *chan;
1026 bConstraintChannel *conchan;
1027 bActionStrip *strip, *nextstrip;
1029 if (!okee("Erase selected keys"))
1032 for (base = G.scene->base.first; base; base=base->next){
1034 /* Delete object ipos */
1035 delete_ipo_keys(base->object->ipo);
1037 /* Delete object constraint keys */
1038 for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
1039 delete_ipo_keys(conchan->ipo);
1041 /* Delete NLA strips */
1042 for (strip = base->object->nlastrips.first; strip; strip=nextstrip){
1043 nextstrip=strip->next;
1044 if (strip->flag & ACTSTRIP_SELECT){
1045 free_actionstrip(strip);
1046 BLI_remlink(&base->object->nlastrips, strip);
1051 /* Delete action ipos */
1052 if (base->object->action){
1053 for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
1054 delete_ipo_keys(chan->ipo);
1055 /* Delete action constraint keys */
1056 for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1057 delete_ipo_keys(conchan->ipo);
1062 BIF_undo_push("Delete NLA keys");
1063 recalc_all_ipos(); // bad
1064 allspace(REMAKEIPO,0);
1065 allqueue (REDRAWVIEW3D, 0);
1066 allqueue(REDRAWNLA, 0);
1067 allqueue(REDRAWIPO, 0);
1070 void duplicate_nlachannel_keys(void)
1073 bActionChannel *chan;
1074 bConstraintChannel *conchan;
1075 bActionStrip *strip, *laststrip;
1077 /* Find selected items */
1078 for (base = G.scene->base.first; base; base=base->next){
1079 /* Duplicate object keys */
1080 duplicate_ipo_keys(base->object->ipo);
1082 /* Duplicate object constraint keys */
1083 for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
1084 duplicate_ipo_keys(conchan->ipo);
1086 /* Duplicate nla strips */
1087 laststrip = base->object->nlastrips.last;
1088 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
1089 if (strip->flag & ACTSTRIP_SELECT){
1090 bActionStrip *newstrip;
1092 copy_actionstrip(&newstrip, &strip);
1094 BLI_addtail(&base->object->nlastrips, newstrip);
1096 strip->flag &= ~ACTSTRIP_SELECT;
1097 newstrip->flag |= ACTSTRIP_SELECT;
1098 set_active_strip(base->object, newstrip);
1101 if (strip==laststrip)
1105 /* Duplicate actionchannel keys */
1106 if (base->object->action){
1107 for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
1108 duplicate_ipo_keys(chan->ipo);
1109 /* Duplicate action constraint keys */
1110 for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1111 duplicate_ipo_keys(conchan->ipo);
1116 BIF_undo_push("Duplicate NLA");
1117 transform_nlachannel_keys ('g', 0);
1120 void borderselect_nla(void)
1125 int val, selectmode;
1128 bActionStrip *strip;
1129 bConstraintChannel *conchan;
1131 if ( (val = get_border (&rect, 3)) ){
1132 if (val == LEFTMOUSE)
1133 selectmode = SELECT_ADD;
1135 selectmode = SELECT_SUBTRACT;
1138 mval[1]= rect.ymin+2;
1139 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1141 mval[1]= rect.ymax-2;
1142 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1144 ymax = count_nla_levels();
1145 ymax*= (NLACHANNELHEIGHT+NLACHANNELSKIP);
1146 ymax+= (NLACHANNELHEIGHT+NLACHANNELSKIP)/2;
1148 for (base=G.scene->base.first; base; base=base->next){
1149 if (nla_filter(base)) {
1151 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1153 /* Check object ipos */
1154 if (base->object->ipo){
1155 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
1156 borderselect_ipo_key(base->object->ipo, rectf.xmin, rectf.xmax,
1159 /* Check object constraint ipos */
1160 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
1161 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
1162 borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax,
1168 /* Check action ipos */
1169 if (base->object->action){
1170 bActionChannel *chan;
1173 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1175 /* if action is mapped in NLA, it returns a correction */
1176 xmin= get_action_frame(base->object, rectf.xmin);
1177 xmax= get_action_frame(base->object, rectf.xmax);
1179 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1180 for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
1181 borderselect_ipo_key(chan->ipo, xmin, xmax, selectmode);
1182 /* Check action constraint ipos */
1183 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1184 borderselect_ipo_key(conchan->ipo, xmin, xmax, selectmode);
1189 } /* End of if action */
1191 /* Skip nlastrips */
1192 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
1193 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1195 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1196 if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
1198 strip->flag |= ACTSTRIP_SELECT;
1200 strip->flag &= ~ACTSTRIP_SELECT;
1208 BIF_undo_push("Border select NLA");
1209 allqueue(REDRAWNLA, 0);
1210 allqueue(REDRAWACTION, 0);
1211 allqueue(REDRAWIPO, 0);
1215 /* right hand side of window, does ipokeys, actionkeys or strips */
1216 static void mouse_nla(int selectmode)
1220 bActionChannel *chan;
1221 bActionStrip *rstrip;
1222 bConstraintChannel *conchan;
1225 short sel, isdone=0;
1227 getmouseco_areawin (mval);
1229 /* Try object ipo or ob-constraint ipo selection */
1230 base= get_nearest_nlachannel_ob_key(&selx, &sel);
1234 if (selectmode == SELECT_REPLACE){
1235 deselect_nlachannel_keys(0);
1236 selectmode = SELECT_ADD;
1239 select_ipo_key(base->object->ipo, selx, selectmode);
1241 /* Try object constraint selection */
1242 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
1243 select_ipo_key(conchan->ipo, selx, selectmode);
1246 /* Try action ipo selection */
1247 act= get_nearest_nlachannel_ac_key(&selx, &sel);
1251 if (selectmode == SELECT_REPLACE){
1252 deselect_nlachannel_keys(0);
1253 selectmode = SELECT_ADD;
1256 for (chan=act->chanbase.first; chan; chan=chan->next) {
1257 select_ipo_key(chan->ipo, selx, selectmode);
1258 /* Try action constraint selection */
1259 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
1260 select_ipo_key(conchan->ipo, selx, selectmode);
1265 /* Try nla strip selection */
1266 base= get_nearest_nlastrip(&rstrip, &sel);
1270 if (!(G.qual & LR_SHIFTKEY)){
1271 deselect_nlachannel_keys(0);
1276 rstrip->flag &= ~ACTSTRIP_SELECT;
1278 rstrip->flag |= ACTSTRIP_SELECT;
1280 set_active_strip(base->object, rstrip);
1286 std_rmouse_transform(transform_nlachannel_keys);
1288 allqueue(REDRAWIPO, 0);
1289 allqueue(REDRAWVIEW3D, 0);
1290 allqueue(REDRAWNLA, 0);
1294 /* This function is currently more complicated than it seems like it should be.
1295 * However, this will be needed once the nla strip timeline is more complex */
1296 static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel)
1298 Base *base, *firstbase=NULL;
1299 bActionStrip *strip, *firststrip=NULL, *foundstrip=NULL;
1305 getmouseco_areawin (mval);
1308 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1311 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1313 ymax = count_nla_levels();
1314 ymax*=(NLACHANNELHEIGHT + NLACHANNELSKIP);
1315 ymax+= NLACHANNELHEIGHT/2;
1317 for (base = G.scene->base.first; base; base=base->next){
1318 if (nla_filter(base)) {
1320 /* Skip object ipos */
1321 ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
1323 /* Skip action ipos */
1324 if (base->object->action)
1325 ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
1328 for (strip=base->object->nlastrips.first; strip; strip=strip->next){
1329 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1331 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1333 if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
1337 *sel = strip->flag & ACTSTRIP_SELECT;
1340 if (strip->flag & ACTSTRIP_SELECT){
1346 else if (foundsel && strip != foundstrip){
1361 static Base *get_nearest_nlachannel_ob_key (float *index, short *sel)
1365 Base *firstbase=NULL;
1366 bConstraintChannel *conchan;
1368 float firstvertx=-1, foundx=-1;
1376 getmouseco_areawin (mval);
1379 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1382 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1384 ymax = count_nla_levels();
1386 ymax*= (NLACHANNELHEIGHT + NLACHANNELSKIP);
1387 ymax+= NLACHANNELHEIGHT/2;
1391 for (base=G.scene->base.first; base; base=base->next){
1392 if (nla_filter(base)) {
1394 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1396 /* Handle object ipo selection */
1397 if (base->object->ipo){
1398 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1399 for (icu=base->object->ipo->curve.first; icu; icu=icu->next){
1400 for (i=0; i<icu->totvert; i++){
1401 if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
1404 firstvertx=icu->bezt[i].vec[1][0];
1405 *sel = icu->bezt[i].f2 & 1;
1408 if (icu->bezt[i].f2 & 1){
1411 foundx = icu->bezt[i].vec[1][0];
1414 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
1415 *index=icu->bezt[i].vec[1][0];
1424 /* Handle object constraint ipos */
1425 for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
1426 if ( !((ymax < rectf.ymin) || (ymin > rectf.ymax)) && conchan->ipo){
1427 for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
1428 for (i=0; i<icu->totvert; i++){
1429 if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
1432 firstvertx=icu->bezt[i].vec[1][0];
1433 *sel = icu->bezt[i].f2 & 1;
1436 if (icu->bezt[i].f2 & 1){
1439 foundx = icu->bezt[i].vec[1][0];
1442 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
1443 *index=icu->bezt[i].vec[1][0];
1455 /* Skip action ipos */
1456 if (base->object->action){
1457 ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
1459 /* Skip nlastrips */
1460 ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
1468 static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel)
1472 bAction *firstact=NULL;
1473 bActionChannel *chan;
1474 bConstraintChannel *conchan;
1476 float firstvert=-1, foundx=-1;
1477 float ymin, ymax, xmin, xmax;
1484 getmouseco_areawin (mval);
1487 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
1490 areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
1492 ymax = count_nla_levels();
1494 ymax*= (NLACHANNELHEIGHT + NLACHANNELSKIP);
1495 ymax+= NLACHANNELHEIGHT/2;
1499 for (base=G.scene->base.first; base; base=base->next){
1500 /* Handle object ipo selection */
1501 if (nla_filter(base)) {
1503 /* Skip object ipo and ob-constraint ipo */
1504 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1507 /* Handle action ipos */
1508 if (base->object->action){
1509 bAction *act= base->object->action;
1511 /* if action is mapped in NLA, it returns a correction */
1512 xmin= get_action_frame(base->object, rectf.xmin);
1513 xmax= get_action_frame(base->object, rectf.xmax);
1515 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1516 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
1517 for (chan=act->chanbase.first; chan; chan=chan->next){
1519 for (icu=chan->ipo->curve.first; icu; icu=icu->next){
1520 for (i=0; i<icu->totvert; i++){
1521 if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] <= xmax ){
1524 firstvert=icu->bezt[i].vec[1][0];
1525 *sel = icu->bezt[i].f2 & 1;
1528 if (icu->bezt[i].f2 & 1){
1531 foundx = icu->bezt[i].vec[1][0];
1534 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
1535 *index=icu->bezt[i].vec[1][0];
1544 for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
1545 ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
1546 if ( !((ymax < rectf.ymin) || (ymin > rectf.ymax)) && conchan->ipo){
1547 for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
1548 for (i=0; i<icu->totvert; i++){
1549 if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] <= xmax ){
1551 firstact=base->object->action;
1552 firstvert=icu->bezt[i].vec[1][0];
1553 *sel = icu->bezt[i].f2 & 1;
1556 if (icu->bezt[i].f2 & 1){
1559 foundx = icu->bezt[i].vec[1][0];
1562 else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
1563 *index=icu->bezt[i].vec[1][0];
1565 return base->object->action;
1580 /* Skip nlastrips */
1581 ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
1589 void deselect_nlachannels(int test)
1595 for (base=G.scene->base.first; base; base=base->next){
1596 /* Check base flags for previous selection */
1597 if (base->flag & SELECT){
1606 /* Select objects */
1607 for (base=G.scene->base.first; base; base=base->next){
1609 if (nla_filter(base))
1610 base->flag |= SELECT;
1613 base->flag &= ~SELECT;
1615 base->object->flag= base->flag;