Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/src/editnla.c')
-rw-r--r--source/blender/src/editnla.c1738
1 files changed, 1738 insertions, 0 deletions
diff --git a/source/blender/src/editnla.c b/source/blender/src/editnla.c
new file mode 100644
index 00000000000..54ee4682c0e
--- /dev/null
+++ b/source/blender/src/editnla.c
@@ -0,0 +1,1738 @@
+/**
+* $Id$
+*
+ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. The Blender
+ * Foundation also sells licenses for use in proprietary software under
+ * the Blender License. See http://www.blender.org/BL/ for information
+ * about this.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL/BL DUAL LICENSE BLOCK *****
+* This file is a horrible mess: An attmept to cram some
+* final functionality into blender before it is too late.
+*
+* Hopefully it can be tidied up at a later date...
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "PIL_time.h"
+
+#include "BKE_global.h"
+#include "BKE_main.h"
+#include "BKE_library.h"
+#include "BKE_nla.h"
+#include "BKE_action.h"
+
+#include "BIF_screen.h"
+#include "BIF_interface.h"
+#include "BIF_buttons.h"
+#include "BIF_space.h"
+#include "BIF_mywindow.h"
+#include "BIF_editview.h"
+#include "BIF_toolbox.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_ipo_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_object_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_action_types.h"
+#include "DNA_nla_types.h"
+#include "DNA_constraint_types.h"
+
+#include "BSE_editipo.h"
+#include "BSE_editnla_types.h"
+#include "BSE_headerbuttons.h"
+#include "BSE_drawipo.h"
+#include "BSE_trans_types.h"
+#include "BSE_edit.h"
+#include "BDR_editobject.h"
+
+#include "interface.h"
+#include "blendef.h"
+#include "mydevice.h"
+#include "blendertimer.h"
+#include "license_key.h"
+#include "keyed_functions.h"
+
+/* Note: A lot of these pretty much duplicate the behaviour of the
+action windows. The functions should be shared, not copy-pasted */
+typedef struct NlaParam{
+ SpaceNla *snla;
+ unsigned short event;
+ short val;
+}NlaParam;
+
+static void deselect_nlachannel_keys (int test);
+static void deselect_nlachannels(int test);
+static void transform_nlachannel_keys(char mode);
+static void delete_nlachannel_keys(void);
+static void delete_nlachannels(void);
+static void duplicate_nlachannel_keys(void);
+static void borderselect_nla(void);
+static void mouse_nla(void);
+static Base *get_nearest_nlachannel_ob_key (float *index, short *sel);
+static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel);
+static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel);
+
+static void mouse_nlachannels(short mval[2]);
+static void add_nlablock(short mval[2]);
+static bActionStrip *get_active_nlastrip(void);
+static void convert_nla(short mval[2]);
+
+extern int count_nla_levels(void); /* From drawnla.c */
+extern int nla_filter (Base* base, int flags); /* From drawnla.c */
+
+/* ******************** SPACE: NLA ********************** */
+
+/* Protected creator function */
+int calc_memleak (void* ptr){
+ int doredraw= 0;
+ short mval[2];
+ float dx,dy;
+ int cfra;
+ SpaceNla *snla;
+ NlaParam *params=(NlaParam*) ptr;
+ unsigned short event;
+ short val ;
+
+ if (!ptr)
+ return -1;
+
+ snla= params->snla;
+ event = params->event;
+ val = params->val;
+
+ if (LICENSE_KEY_VALID){
+ if(curarea->win==0) return 0;
+
+ if (!snla)
+ return 0;
+
+ if(val) {
+ if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
+
+ getmouseco_areawin(mval);
+
+ switch(event) {
+ case UI_BUT_EVENT:
+ do_blenderbuttons(val);
+ break;
+ case HOMEKEY:
+ do_nla_buttons(B_NLAHOME);
+ break;
+ case DKEY:
+ if (G.qual & LR_SHIFTKEY && mval[0]>=NLAWIDTH){
+ duplicate_nlachannel_keys();
+ update_for_newframe();
+ }
+ break;
+ case DELKEY:
+ case XKEY:
+ if (mval[0]>=NLAWIDTH)
+ delete_nlachannel_keys ();
+ else
+ delete_nlachannels();
+ update_for_newframe();
+ break;
+ case GKEY:
+ if (mval[0]>=NLAWIDTH)
+ transform_nlachannel_keys ('g');
+ update_for_newframe();
+ break;
+ case SKEY:
+ if (mval[0]>=NLAWIDTH)
+ transform_nlachannel_keys ('s');
+ update_for_newframe();
+ break;
+ case BKEY:
+ borderselect_nla();
+ break;
+ case CKEY:
+ convert_nla(mval);
+ break;
+
+ case AKEY:
+ if (G.qual & LR_SHIFTKEY){
+ add_nlablock(mval);
+ allqueue (REDRAWNLA, 0);
+ allqueue (REDRAWVIEW3D, 0);
+ }
+ else{
+ if (mval[0]>=NLAWIDTH)
+ deselect_nlachannel_keys(1);
+ else{
+ deselect_nlachannels(1);
+ allqueue (REDRAWVIEW3D, 0);
+ }
+ allqueue (REDRAWNLA, 0);
+ allqueue (REDRAWIPO, 0);
+ }
+ break;
+ case RIGHTMOUSE:
+ if (mval[0]>=NLAWIDTH)
+ mouse_nla();
+ else
+ mouse_nlachannels(mval);
+ break;
+ case LEFTMOUSE:
+ if (mval[0]>NLAWIDTH){
+ do {
+ getmouseco_areawin(mval);
+
+ areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
+
+ cfra= (int)dx;
+ if(cfra< 1) cfra= 1;
+
+ if( cfra!=CFRA ) {
+ CFRA= cfra;
+ update_for_newframe();
+ force_draw_plus(SPACE_VIEW3D);
+ force_draw_plus(SPACE_IPO);
+ }
+
+ } while(get_mbut()&L_MOUSE);
+ }
+
+ break;
+ case MIDDLEMOUSE:
+ view2dmove(); /* in drawipo.c */
+ break;
+ }
+ }
+
+ if(doredraw) scrarea_queue_winredraw(curarea);
+ }
+ return 0;
+}
+
+void winqreadnlaspace(unsigned short event, short val, char ascii)
+{
+ NlaParam param;
+ Base *base;
+ bActionStrip *strip, *next;
+ short mval[2];
+ float dx, dy;
+ int cfra;
+
+ param.event = event;
+ param.val = val;
+ param.snla = curarea->spacedata.first;
+
+
+ /* Call the protected (&obfuscated) eventloop function */
+ if (KEY_NLA_EVENT){
+ KEY_NLA_EVENT(&param);
+ }
+ else{
+ getmouseco_areawin(mval);
+ switch(event) {
+ case GKEY:
+ case SKEY:
+ case AKEY:
+ case CKEY:
+ case NKEY:
+ case RIGHTMOUSE:
+ notice ("NLA window editing only available in Blender Publisher");
+ break;
+ case LEFTMOUSE:
+ if (mval[0]>NLAWIDTH){
+ do {
+ getmouseco_areawin(mval);
+
+ areamouseco_to_ipoco(G.v2d, mval, &dx, &dy);
+
+ cfra= (int)dx;
+ if(cfra< 1) cfra= 1;
+
+ if( cfra!=CFRA ) {
+ CFRA= cfra;
+ update_for_newframe();
+ force_draw_plus(SPACE_VIEW3D);
+ force_draw_plus(SPACE_IPO);
+ }
+
+ } while(get_mbut()&L_MOUSE);
+ }
+
+ break;
+ case MIDDLEMOUSE:
+ view2dmove(); /* in drawipo.c */
+ break;
+ case DELKEY:
+ case XKEY:
+ if (okee ("This will remove all NLA information from all objects!")){
+ for (base = G.scene->base.first; base; base=base->next){
+ for (strip=base->object->nlastrips.first; strip; strip=next){
+ next=strip->next;
+ free_actionstrip(strip);
+ BLI_freelinkN(&base->object->nlastrips, strip);
+ }
+ }
+ update_for_newframe();
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+static void convert_nla(short mval[2])
+{
+ short event;
+ float ymax, ymin;
+ Base *base;
+ float x,y;
+ int sel=0;
+ bActionStrip *strip, *nstrip;
+ if (LICENSE_KEY_VALID){
+ /* Find out what strip we're over */
+ ymax = count_nla_levels() * (NLACHANNELSKIP+NLACHANNELHEIGHT);
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+
+ for (base=G.scene->base.first; base; base=base->next){
+ if (nla_filter(base, 0)){
+ /* Check object ipo */
+ ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
+ if (y>=ymin && y<=ymax)
+ break;
+ ymax=ymin;
+
+ if (base->object->type==OB_ARMATURE){
+ /* Check action ipo */
+ ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
+ if (y>=ymin && y<=ymax)
+ break;
+ ymax=ymin;
+
+ /* Check nlastrips */
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+ ymin=ymax-(NLACHANNELSKIP+NLACHANNELHEIGHT);
+ if (y>=ymin && y<=ymax){
+ sel = 1;
+ break;
+ }
+ ymax=ymin;
+ }
+ if (sel)
+ break;
+ }
+ }
+ }
+
+ if (!base)
+ return;
+
+ if (base->object->type==OB_ARMATURE){
+ event = pupmenu("Convert%t|Action to NLAstrip%x1");
+ switch (event){
+ case 1:
+ if (base->object->action){
+ /* Make new actionstrip */
+ nstrip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
+
+ deselect_nlachannel_keys(0);
+
+ /* Link the action to the nstrip */
+ nstrip->act = base->object->action;
+ nstrip->actstart = calc_action_start(base->object->action); /* MAKE THIS THE FIRST FRAME OF THE ACTION */
+ nstrip->actend = calc_action_end(base->object->action);
+ nstrip->start = nstrip->actstart;
+ nstrip->end = nstrip->actend;
+ nstrip->flag = ACTSTRIP_SELECT;
+ nstrip->repeat = 1.0;
+
+ BLI_addtail(&base->object->nlastrips, nstrip);
+
+ /* Unlink action */
+ base->object->action = NULL;
+
+ allqueue (REDRAWNLA, 0);
+ }
+
+
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+static void add_nlablock(short mval[2])
+{
+ /* Make sure we are over an armature */
+ Base *base;
+ bAction *act=NULL;
+ bActionStrip *strip;
+ int foundsel=0;
+ float ymin, ymax;
+ float x, y;
+ rctf rectf;
+ short event;
+ char *str;
+ short nr;
+ int cur;
+
+ if (LICENSE_KEY_VALID){
+ areamouseco_to_ipoco(G.v2d, mval, &x, &y);
+
+ mval[0]-=7;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+
+ mval[0]+=14;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ ymax = count_nla_levels();
+ ymax*=(NLACHANNELHEIGHT + NLACHANNELSKIP);
+
+ for (base=G.scene->base.first; base; base=base->next){
+ /* Handle object ipo selection */
+ if (nla_filter(base, 0)){
+
+ /* STUPID STUPID STUPID */
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+
+ /* Handle object ipos */
+ if (base->object->type==OB_ARMATURE){
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
+ break;
+ }
+
+ ymax=ymin;
+
+ /* Handle action ipos & Action strips */
+ if (base->object->type==OB_ARMATURE){
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP)*(BLI_countlist(&base->object->nlastrips) + 1);
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
+ break;
+ ymax=ymin;
+
+
+ }
+ }
+ }
+
+ /* Make sure we have an armature */
+ if (!base){
+ error ("Not an armature!");
+ return;
+ }
+
+ /* Popup action menu */
+ IDnames_to_pupstring(&str, "Add action", NULL, &G.main->action, (ID *)G.scene, &nr);
+
+ event = pupmenu(str);
+
+ if (event!=-1){
+ for (cur = 1, act=G.main->action.first; act; act=act->id.next, cur++){
+ if (cur==event){
+ break;
+ }
+ }
+ }
+
+ MEM_freeN(str);
+
+ /* Bail out if no action was chosen */
+ if (!act){
+ return;
+ }
+
+ /* Initialize the new action block */
+ strip = MEM_callocN(sizeof(bActionStrip), "bActionStrip");
+
+ deselect_nlachannel_keys(0);
+
+ /* Link the action to the strip */
+ strip->act = act;
+ strip->actstart = 1.0;
+ strip->actend = calc_action_end(act);
+ strip->start = G.scene->r.cfra; /* Should be mval[0] */
+ strip->end = strip->start + (strip->actend-strip->actstart);
+ strip->flag = ACTSTRIP_SELECT;
+ strip->repeat = 1.0;
+
+ act->id.us++;
+
+ BLI_addtail(&base->object->nlastrips, strip);
+ }
+}
+
+static void mouse_nlachannels(short mval[2])
+{
+ /* Find which strip has been clicked */
+// bActionChannel *chan;
+ bConstraintChannel *conchan=NULL;
+ bActionStrip *strip;
+ float click;
+ int wsize;
+ int sel;
+ Base *base;
+
+ wsize = (count_nla_levels ()*(NLACHANNELHEIGHT+NLACHANNELSKIP));
+
+
+ click = (wsize-(mval[1]+G.v2d->cur.ymin));
+ click += NLACHANNELHEIGHT/2;
+ click /= (NLACHANNELHEIGHT+NLACHANNELSKIP);
+
+ if (click<0)
+ return;
+
+ for (base = G.scene->base.first; base; base=base->next){
+ if (nla_filter(base, 0)){
+ /* See if this is a base selected */
+ if ((int)click==0)
+ break;
+
+ click--;
+
+ /* Check for click in a constraint */
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
+ if ((int)click==0){
+ base=G.scene->base.last;
+ break;
+ }
+ click--;
+ }
+
+ /* See if this is an action */
+ if (base->object->type==OB_ARMATURE && base->object->action){
+ if ((int)click==0){
+ break;
+ }
+ click--;
+ }
+
+ /* See if this is an nla strip */
+ for (strip = base->object->nlastrips.first; strip; strip=strip->next){
+ if ((int)click==0){
+ base=G.scene->base.last;
+ break;
+ }
+ click--;
+ }
+ }
+ }
+
+ if (!base && !conchan)
+ return;
+
+ /* Handle constraint strip selection */
+ if (conchan){
+ if (conchan->flag & CONSTRAINT_CHANNEL_SELECT)
+ sel = 0;
+ else
+ sel =1;
+
+ /* Channel names clicking */
+ if (G.qual & LR_SHIFTKEY){
+ // select_poseelement_by_name(chan->name, !(chan->flag & ACHAN_SELECTED));
+ if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
+ conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
+ // hilight_channel(act, chan, 0);
+ }
+ else{
+ conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
+ // hilight_channel(act, chan, 1);
+ }
+ }
+ else{
+ deselect_nlachannels (0); // Auto clear
+ conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
+ // hilight_channel(act, chan, 1);
+ // act->achan = chan;
+ // select_poseelement_by_name(chan->name, 1);
+ }
+
+ }
+
+ /* Handle object strip selection */
+ else if (base)
+ {
+ /* Choose the mode */
+ if (base->flag & SELECT)
+ sel = 0;
+ else
+ sel =1;
+
+ /* Channel names clicking */
+ if (G.qual & LR_SHIFTKEY){
+ // select_poseelement_by_name(chan->name, !(chan->flag & ACHAN_SELECTED));
+ if (base->flag & SELECT){
+ base->flag &= ~SELECT;
+ // hilight_channel(act, chan, 0);
+ }
+ else{
+ base->flag |= SELECT;
+ // hilight_channel(act, chan, 1);
+ }
+ }
+ else{
+ deselect_nlachannels (0); // Auto clear
+ base->flag |= SELECT;
+ // hilight_channel(act, chan, 1);
+ // act->achan = chan;
+ // select_poseelement_by_name(chan->name, 1);
+ }
+
+ }
+ allqueue (REDRAWIPO, 0);
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWACTION, 0);
+ allqueue(REDRAWNLA, 0);
+
+}
+
+void init_nlaspace(ScrArea *sa)
+{
+ SpaceNla *snla;
+
+ snla= MEM_callocN(sizeof(SpaceNla), "initnlaspace");
+ BLI_addhead(&sa->spacedata, snla);
+
+ snla->spacetype= SPACE_NLA;
+
+ snla->v2d.tot.xmin= 1.0;
+ snla->v2d.tot.ymin= 0.0;
+ snla->v2d.tot.xmax= 1000.0;
+ snla->v2d.tot.ymax= 1000.0;
+
+ snla->v2d.cur.xmin= -5.0;
+ snla->v2d.cur.ymin= 0.0;
+ snla->v2d.cur.xmax= 65.0;
+ snla->v2d.cur.ymax= 1000.0;
+
+ snla->v2d.min[0]= 0.0;
+ snla->v2d.min[1]= 0.0;
+
+ snla->v2d.max[0]= 1000.0;
+ snla->v2d.max[1]= 1000.0;
+
+ snla->v2d.minzoom= 0.1F;
+ snla->v2d.maxzoom= 10;
+
+ snla->v2d.scroll= R_SCROLL+B_SCROLL;
+ snla->v2d.keepaspect= 0;
+ snla->v2d.keepzoom= V2D_LOCKZOOM_Y;
+ snla->v2d.keeptot= 0;
+
+ snla->lock = 0;
+};
+
+static void deselect_nlachannel_keys (int test)
+{
+ Base *base;
+ int sel=1;
+ bActionChannel *chan;
+ bActionStrip *strip;
+ bConstraintChannel *conchan;
+
+ /* Determine if this is selection or deselection */
+ if (LICENSE_KEY_VALID){
+ if (test){
+ for (base=G.scene->base.first; base && sel; base=base->next){
+
+ /* Test object ipos */
+ if (is_ipo_key_selected(base->object->ipo)){
+ sel = 0;
+ break;
+ }
+
+ /* Test object constraint ipos */
+ if (sel){
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
+ if (is_ipo_key_selected(conchan->ipo)){
+ sel=0;
+ break;
+ }
+ }
+ }
+
+ /* Test action ipos */
+ if (sel){
+ if (base->object->type==OB_ARMATURE && base->object->action){
+ for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
+ if (is_ipo_key_selected(chan->ipo)){
+ sel=0;
+ break;
+ }
+
+ /* Test action constraints */
+ if (sel){
+ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
+ if (is_ipo_key_selected(conchan->ipo)){
+ sel=0;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Test NLA strips */
+ if (sel){
+ if (base->object->type==OB_ARMATURE){
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+ if (strip->flag & ACTSTRIP_SELECT){
+ sel = 0;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ sel=0;
+
+
+ /* Set the flags */
+ for (base=G.scene->base.first; base; base=base->next){
+ /* Set the object ipos */
+ set_ipo_key_selection(base->object->ipo, sel);
+
+
+ /* Set the object constraint ipos */
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
+ set_ipo_key_selection(conchan->ipo, sel);
+ }
+
+ /* Set the action ipos */
+ if (base->object->type==OB_ARMATURE && base->object->action){
+ for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
+ set_ipo_key_selection(chan->ipo, sel);
+ /* Set the action constraint ipos */
+ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
+ set_ipo_key_selection(conchan->ipo, sel);
+ }
+ }
+
+ /* Set the nlastrips */
+ if (base->object->type==OB_ARMATURE){
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+ if (sel)
+ strip->flag |= ACTSTRIP_SELECT;
+ else
+ strip->flag &= ~ACTSTRIP_SELECT;
+ }
+ }
+ }
+ }
+}
+
+
+static void transform_nlachannel_keys(char mode)
+{
+ Base *base;
+ TransVert *tv;
+ int /*sel=0,*/ i;
+ short mvals[2], mvalc[2];
+ // short cent[2];
+ float sval[2], cval[2], lastcval[2];
+ short cancel=0;
+ float fac=0.0F;
+ int loop=1;
+ int tvtot=0;
+ float deltax, startx;
+ // float cenf[2];
+ int invert=0, firsttime=1;
+ char str[256];
+ bActionChannel *chan;
+ bActionStrip *strip;
+ bConstraintChannel *conchan;
+
+ if (LICENSE_KEY_VALID){
+ /* Ensure that partial selections result in beztriple selections */
+ for (base=G.scene->base.first; base; base=base->next){
+
+ /* Check object ipos */
+ tvtot+=fullselect_ipo_keys(base->object->ipo);
+
+ /* Check object constraint ipos */
+ for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
+ tvtot+=fullselect_ipo_keys(conchan->ipo);
+
+ /* Check action ipos */
+ if (base->object->type == OB_ARMATURE && base->object->action){
+ for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
+ tvtot+=fullselect_ipo_keys(chan->ipo);
+
+ /* Check action constraint ipos */
+ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
+ tvtot+=fullselect_ipo_keys(conchan->ipo);
+ }
+
+ }
+
+ /* Check nlastrips */
+ if (base->object->type==OB_ARMATURE){
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+ if (strip->flag & ACTSTRIP_SELECT)
+ tvtot+=2;
+ }
+ }
+ }
+
+ /* If nothing is selected, bail out */
+ if (!tvtot)
+ return;
+
+
+ /* Build the transvert structure */
+ tv = MEM_callocN (sizeof(TransVert) * tvtot, "transVert");
+ tvtot=0;
+ for (base=G.scene->base.first; base; base=base->next){
+ /* Manipulate object ipos */
+ tvtot=add_trans_ipo_keys(base->object->ipo, tv, tvtot);
+
+ /* Manipulate object constraint ipos */
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
+ tvtot=add_trans_ipo_keys(conchan->ipo, tv, tvtot);
+
+ /* Manipulate action ipos */
+ if (base->object->type==OB_ARMATURE && base->object->action){
+ for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
+ tvtot=add_trans_ipo_keys(chan->ipo, tv, tvtot);
+
+ /* Manipulate action constraint ipos */
+ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
+ tvtot=add_trans_ipo_keys(conchan->ipo, tv, tvtot);
+ }
+ }
+
+ /* Manipulate nlastrips */
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+ if (strip->flag & ACTSTRIP_SELECT){
+ tv[tvtot+0].val=&strip->start;
+ tv[tvtot+1].val=&strip->end;
+
+ tv[tvtot+0].oldval = strip->start;
+ tv[tvtot+1].oldval = strip->end;
+
+ tvtot+=2;
+ }
+ }
+ }
+
+ /* Do the event loop */
+ // cent[0] = curarea->winx + (G.snla->v2d.hor.xmax)/2;
+ // cent[1] = curarea->winy + (G.snla->v2d.hor.ymax)/2;
+
+ // areamouseco_to_ipoco(cent, &cenf[0], &cenf[1]);
+
+ getmouseco_areawin (mvals);
+ areamouseco_to_ipoco(G.v2d, mvals, &sval[0], &sval[1]);
+
+ startx=sval[0];
+ while (loop) {
+ /* Get the input */
+ /* If we're cancelling, reset transformations */
+ /* Else calc new transformation */
+ /* Perform the transformations */
+ while (qtest()) {
+ short val;
+ unsigned short event= extern_qread(&val);
+
+ if (val) {
+ switch (event) {
+ case LEFTMOUSE:
+ case SPACEKEY:
+ case RETKEY:
+ loop=0;
+ break;
+ case XKEY:
+ break;
+ case ESCKEY:
+ case RIGHTMOUSE:
+ cancel=1;
+ loop=0;
+ break;
+ default:
+ arrows_move_cursor(event);
+ break;
+ };
+ }
+ }
+
+ if (cancel) {
+ for (i=0; i<tvtot; i++) {
+ if (tv[i].loc){
+ tv[i].loc[0]=tv[i].oldloc[0];
+ tv[i].loc[1]=tv[i].oldloc[1];
+ }
+ if (tv[i].val)
+ tv[i].val[0]=tv[i].oldval;
+ }
+ }
+ else {
+ getmouseco_areawin (mvalc);
+ areamouseco_to_ipoco(G.v2d, mvalc, &cval[0], &cval[1]);
+
+ if (!firsttime && lastcval[0]==cval[0] && lastcval[1]==cval[1]) {
+ PIL_sleep_ms(1);
+ }
+ else {
+ for (i=0; i<tvtot; i++){
+ if (tv[i].loc)
+ tv[i].loc[0]=tv[i].oldloc[0];
+ if (tv[i].val)
+ tv[i].val[0]=tv[i].oldval;
+
+ switch (mode){
+ case 'g':
+ deltax = cval[0]-sval[0];
+ fac= deltax;
+
+ apply_keyb_grid(&fac, 0.0F, 1.0F, 0.1F, U.flag & AUTOGRABGRID);
+
+ if (tv[i].loc)
+ tv[i].loc[0]+=fac;
+ if (tv[i].val)
+ tv[i].val[0]+=fac;
+ break;
+ case 's':
+ startx=mvals[0]-(NLAWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
+ deltax=mvalc[0]-(NLAWIDTH/2+(curarea->winrct.xmax-curarea->winrct.xmin)/2);
+ fac= (float)fabs(deltax/startx);
+
+ apply_keyb_grid(&fac, 0.0F, 0.2F, 0.1F, U.flag & AUTOSIZEGRID);
+
+ if (invert){
+ if (i % 03 == 0){
+ memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i+2].oldloc));
+ }
+ if (i % 03 == 2){
+ memcpy (tv[i].loc, tv[i].oldloc, sizeof(tv[i-2].oldloc));
+ }
+
+ fac*=-1;
+ }
+ startx= (G.scene->r.cfra);
+
+ if (tv[i].loc){
+ tv[i].loc[0]-= startx;
+ tv[i].loc[0]*=fac;
+ tv[i].loc[0]+= startx;
+ }
+ if (tv[i].val){
+ tv[i].val[0]-= startx;
+ tv[i].val[0]*=fac;
+ tv[i].val[0]+= startx;
+ }
+
+ break;
+ }
+ }
+ }
+
+ if (mode=='s'){
+ sprintf(str, "sizeX: %.3f", fac);
+ headerprint(str);
+ }
+ else if (mode=='g'){
+ sprintf(str, "deltaX: %.3f", fac);
+ headerprint(str);
+ }
+
+ if (G.snla->lock){
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWNLA, 0);
+ allqueue (REDRAWIPO, 0);
+ force_draw_all();
+ }
+ else {
+ addqueue (curarea->win, REDRAWALL, 0);
+ force_draw ();
+ }
+ }
+
+ lastcval[0]= cval[0];
+ lastcval[1]= cval[1];
+ firsttime= 0;
+ }
+
+ allspace(REMAKEALLIPO, 0);
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWNLA, 0);
+ allqueue (REDRAWIPO, 0);
+ MEM_freeN (tv);
+ }
+}
+
+static void delete_nlachannel_keys(void)
+{
+ Base *base;
+ bActionChannel *chan;
+ bConstraintChannel *conchan;
+ bActionStrip *strip, *nextstrip;
+
+ if (LICENSE_KEY_VALID){
+ if (!okee("Erase selected keys"))
+ return;
+
+ for (base = G.scene->base.first; base; base=base->next){
+
+ /* Delete object ipos */
+ delete_ipo_keys(base->object->ipo);
+
+ /* Delete object constraint keys */
+ for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
+ delete_ipo_keys(conchan->ipo);
+
+ /* Delete NLA strips */
+ if (base->object->type==OB_ARMATURE){
+ for (strip = base->object->nlastrips.first; strip; strip=nextstrip){
+ nextstrip=strip->next;
+ if (strip->flag & ACTSTRIP_SELECT){
+ free_actionstrip(strip);
+ BLI_remlink(&base->object->nlastrips, strip);
+ MEM_freeN(strip);
+ }
+ }
+ }
+
+ /* Delete action ipos */
+ if (base->object->type==OB_ARMATURE && base->object->action){
+ for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
+ delete_ipo_keys(chan->ipo);
+ /* Delete action constraint keys */
+ for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
+ delete_ipo_keys(conchan->ipo);
+ }
+ }
+ }
+
+ allspace(REMAKEALLIPO, 0);
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWIPO, 0);
+ }
+}
+
+static void duplicate_nlachannel_keys(void)
+{
+ Base *base;
+ bActionChannel *chan;
+ bConstraintChannel *conchan;
+ bActionStrip *strip, *laststrip;
+ if (LICENSE_KEY_VALID){
+
+ /* Find selected items */
+ for (base = G.scene->base.first; base; base=base->next){
+ /* Duplicate object keys */
+ duplicate_ipo_keys(base->object->ipo);
+
+ /* Duplicate object constraint keys */
+ for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
+ duplicate_ipo_keys(conchan->ipo);
+
+ /* Duplicate nla strips */
+ if (base->object->type == OB_ARMATURE){
+ laststrip = base->object->nlastrips.last;
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+ if (strip->flag & ACTSTRIP_SELECT){
+ bActionStrip *newstrip;
+
+ copy_actionstrip(&newstrip, &strip);
+
+ BLI_addtail(&base->object->nlastrips, newstrip);
+
+ strip->flag &= ~ACTSTRIP_SELECT;
+ newstrip->flag |= ACTSTRIP_SELECT;
+
+ }
+ if (strip==laststrip)
+ break;
+ }
+ }
+
+ /* Duplicate actionchannel keys */
+ if (base->object->type == OB_ARMATURE && base->object->action){
+ for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
+ duplicate_ipo_keys(chan->ipo);
+ /* Duplicate action constraint keys */
+ for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
+ duplicate_ipo_keys(conchan->ipo);
+ }
+ }
+ }
+
+ transform_nlachannel_keys ('g');
+ }
+}
+
+static void borderselect_nla(void)
+{
+ Base *base;
+ rcti rect;
+ rctf rectf;
+ int val;
+ short mval[2];
+ float ymin, ymax;
+ bActionStrip *strip;
+ bConstraintChannel *conchan;
+
+ if (LICENSE_KEY_VALID){
+ val= get_border (&rect, 3);
+
+ if (val){
+ mval[0]= rect.xmin;
+ mval[1]= rect.ymin+2;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+ mval[0]= rect.xmax;
+ mval[1]= rect.ymax-2;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ ymax = count_nla_levels();
+ ymax*= (NLACHANNELHEIGHT+NLACHANNELSKIP);
+
+ for (base=G.scene->base.first; base; base=base->next){
+ /* Check object ipos */
+ if (nla_filter(base, 0)){
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ if (base->object->ipo){
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
+ borderselect_ipo_key(base->object->ipo, rectf.xmin, rectf.xmax, val);
+ }
+ ymax=ymin;
+
+ /* Check object constraint ipos */
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
+ borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, val);
+ ymax=ymin;
+ }
+
+ /* Check action ipos */
+ if (ACTIVE_ARMATURE(base)){
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ if (base->object->action){
+ bActionChannel *chan;
+
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
+ for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
+ borderselect_ipo_key(chan->ipo, rectf.xmin, rectf.xmax, val);
+ /* Check action constraint ipos */
+ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
+ borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax, val);
+ }
+ }
+ }
+ ymax=ymin;
+ } /* End of if armature */
+
+ /* Skip nlastrips */
+ if (base->object->type==OB_ARMATURE){
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ //
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
+ if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
+ if (val==1)
+ strip->flag |= ACTSTRIP_SELECT;
+ else
+ strip->flag &= ~ACTSTRIP_SELECT;
+ }
+ }
+
+ ymax=ymin;
+ }
+ }
+
+ } /* End of object filter */
+ }
+ allqueue(REDRAWNLA, 0);
+ allqueue(REDRAWACTION, 0);
+ allqueue(REDRAWIPO, 0);
+ }
+ }
+}
+
+static void mouse_nla(void)
+{
+ short sel;
+ float selx;
+ short mval[2];
+ Base *base;
+ bAction *act;
+ bActionChannel *chan;
+ bActionStrip *rstrip;
+ bConstraintChannel *conchan;
+
+ if (LICENSE_KEY_VALID){
+ getmouseco_areawin (mval);
+
+ /* Try object ipo selection */
+ base=get_nearest_nlachannel_ob_key(&selx, &sel);
+ if (base){
+ if (!(G.qual & LR_SHIFTKEY)){
+ deselect_nlachannel_keys(0);
+ sel = 0;
+ }
+
+ select_ipo_key(base->object->ipo, selx, sel);
+
+ /* Try object constraint selection */
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
+ select_ipo_key(conchan->ipo, selx, sel);
+
+
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWNLA, 0);
+ return;
+ }
+
+ /* Try action ipo selection */
+ act=get_nearest_nlachannel_ac_key(&selx, &sel);
+ if (act){
+ if (!(G.qual & LR_SHIFTKEY)){
+ deselect_nlachannel_keys(0);
+ sel = 0;
+ }
+
+ for (chan=act->chanbase.first; chan; chan=chan->next){
+ select_ipo_key(chan->ipo, selx, sel);
+ /* Try action constraint selection */
+ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
+ select_ipo_key(conchan->ipo, selx, sel);
+ }
+
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWNLA, 0);
+ return;
+ }
+
+ /* Try nla strip selection */
+ base=get_nearest_nlastrip(&rstrip, &sel);
+ if (base){
+ if (!(G.qual & LR_SHIFTKEY)){
+ deselect_nlachannel_keys(0);
+ sel = 0;
+ }
+
+ if (sel)
+ rstrip->flag &= ~ACTSTRIP_SELECT;
+ else
+ rstrip->flag |= ACTSTRIP_SELECT;
+
+ allqueue(REDRAWIPO, 0);
+ allqueue(REDRAWVIEW3D, 0);
+ allqueue(REDRAWNLA, 0);
+ return;
+
+ }
+
+ }
+
+}
+
+static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel)
+/* This function is currently more complicated than it seems like it should be.
+* However, this will be needed once the nla strip timeline is more complex */
+{
+ Base *base, *firstbase=NULL;
+ short mval[2];
+ short foundsel = 0;
+ rctf rectf;
+ float ymin, ymax;
+ bActionStrip *strip, *firststrip, *foundstrip;
+
+ if (LICENSE_KEY_VALID){
+ getmouseco_areawin (mval);
+
+ mval[0]-=7;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+
+ mval[0]+=14;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ ymax = count_nla_levels();
+ ymax*=(NLACHANNELHEIGHT + NLACHANNELSKIP);
+
+ for (base = G.scene->base.first; base; base=base->next){
+ if (nla_filter(base, 0)){
+ /* Skip object ipos */
+ // if (base->object->ipo)
+ ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
+
+ if (base->object->type==OB_ARMATURE){
+ /* Skip action ipos */
+ if (base->object->action)
+ ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
+
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ /* Do Ytest */
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
+ /* Do XTest */
+ if (!((rectf.xmax<strip->start) || (rectf.xmin>strip->end))){
+ if (!firstbase){
+ firstbase=base;
+ firststrip=strip;
+ *sel = strip->flag & ACTSTRIP_SELECT;
+ }
+
+ if (strip->flag & ACTSTRIP_SELECT){
+ if (!foundsel){
+ foundsel=1;
+ foundstrip = strip;
+ }
+ }
+ else if (foundsel && strip != foundstrip){
+ *rstrip=strip;
+ *sel = 0;
+ return base;
+ }
+ }
+ }
+ ymax=ymin;
+ }
+ }
+ }
+ }
+ *rstrip=firststrip;
+ return firstbase;
+ }
+ else
+ return NULL;
+}
+
+static Base *get_nearest_nlachannel_ob_key (float *index, short *sel)
+{
+ Base *base;
+ IpoCurve *icu;
+ Base *firstbase=NULL;
+ bConstraintChannel *conchan;
+ int foundsel=0;
+ float firstvert=-1, foundx=-1;
+ int i;
+ short mval[2];
+ float ymin, ymax;
+ rctf rectf;
+
+ if (LICENSE_KEY_VALID){
+ *index=0;
+
+ getmouseco_areawin (mval);
+
+ mval[0]-=7;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+
+ mval[0]+=14;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ ymax = count_nla_levels();
+
+ ymax*=(NLACHANNELHEIGHT + NLACHANNELSKIP);
+
+ *sel=0;
+
+ for (base=G.scene->base.first; base; base=base->next){
+ /* Handle object ipo selection */
+ if (nla_filter(base, 0)){
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ if (base->object->ipo){
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
+ for (icu=base->object->ipo->curve.first; icu; icu=icu->next){
+ for (i=0; i<icu->totvert; i++){
+ if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
+ if (!firstbase){
+ firstbase=base;
+ firstvert=icu->bezt[i].vec[1][0];
+ *sel = icu->bezt[i].f2 & 1;
+ }
+
+ if (icu->bezt[i].f2 & 1){
+ if (!foundsel){
+ foundsel=1;
+ foundx = icu->bezt[i].vec[1][0];
+ }
+ }
+ else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
+ *index=icu->bezt[i].vec[1][0];
+ *sel = 0;
+ return base;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ ymax=ymin;
+
+ /* Handle object constraint ipos */
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
+ for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
+ for (i=0; i<icu->totvert; i++){
+ if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
+ if (!firstbase){
+ firstbase=base;
+ firstvert=icu->bezt[i].vec[1][0];
+ *sel = icu->bezt[i].f2 & 1;
+ }
+
+ if (icu->bezt[i].f2 & 1){
+ if (!foundsel){
+ foundsel=1;
+ foundx = icu->bezt[i].vec[1][0];
+ }
+ }
+ else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
+ *index=icu->bezt[i].vec[1][0];
+ *sel = 0;
+ return base;
+ }
+ }
+ }
+ }
+ }
+ ymax=ymin;
+ }
+
+ /* Skip action ipos */
+ if (ACTIVE_ARMATURE(base)){
+ ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ }
+ /* Skip nlastrips */
+ if (base->object->type==OB_ARMATURE){
+ ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
+ }
+ }
+ }
+
+ *index=firstvert;
+ return firstbase;
+ }
+ else
+ return NULL;
+}
+
+static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel)
+{
+ Base *base;
+ IpoCurve *icu;
+ bAction *firstact=NULL;
+ int foundsel=0;
+ float firstvert=-1, foundx=-1;
+ int i;
+ short mval[2];
+ float ymin, ymax;
+ rctf rectf;
+ bActionChannel *chan;
+ bConstraintChannel *conchan;
+
+ if (LICENSE_KEY_VALID){
+ *index=0;
+
+ getmouseco_areawin (mval);
+
+ mval[0]-=7;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
+
+ mval[0]+=14;
+ areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+
+ ymax = count_nla_levels();
+
+ ymax*=(NLACHANNELHEIGHT + NLACHANNELSKIP);
+
+ *sel=0;
+
+ for (base=G.scene->base.first; base; base=base->next){
+ /* Handle object ipo selection */
+ if (nla_filter(base, 0)){
+ /* Skip object ipo */
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ ymax=ymin;
+
+ /* Handle action ipos */
+ if (ACTIVE_ARMATURE(base)){
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
+ for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
+ for (icu=chan->ipo->curve.first; icu; icu=icu->next){
+ for (i=0; i<icu->totvert; i++){
+ if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
+ if (!firstact){
+ firstact=base->object->action;
+ firstvert=icu->bezt[i].vec[1][0];
+ *sel = icu->bezt[i].f2 & 1;
+ }
+
+ if (icu->bezt[i].f2 & 1){
+ if (!foundsel){
+ foundsel=1;
+ foundx = icu->bezt[i].vec[1][0];
+ }
+ }
+ else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
+ *index=icu->bezt[i].vec[1][0];
+ *sel = 0;
+ return base->object->action;
+ }
+ }
+ }
+ }
+
+
+ for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
+ ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
+ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
+ for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
+ for (i=0; i<icu->totvert; i++){
+ if (icu->bezt[i].vec[1][0] > rectf.xmin && icu->bezt[i].vec[1][0] <= rectf.xmax ){
+ if (!firstact){
+ firstact=base->object->action;
+ firstvert=icu->bezt[i].vec[1][0];
+ *sel = icu->bezt[i].f2 & 1;
+ }
+
+ if (icu->bezt[i].f2 & 1){
+ if (!foundsel){
+ foundsel=1;
+ foundx = icu->bezt[i].vec[1][0];
+ }
+ }
+ else if (foundsel && icu->bezt[i].vec[1][0] != foundx){
+ *index=icu->bezt[i].vec[1][0];
+ *sel = 0;
+ return base->object->action;
+ }
+ }
+ }
+ }
+ }
+ ymax=ymin;
+ }
+
+
+ }
+ }
+ ymax=ymin;
+ }
+
+ /* Skip nlastrips */
+ if (base->object->type==OB_ARMATURE){
+ ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
+ }
+ }
+ }
+
+ *index=firstvert;
+ return firstact;
+ }
+ else
+ return NULL;
+}
+
+static bActionStrip *get_active_nlastrip(void)
+/* For now just returns the first selected strip */
+{
+ Base *base;
+ bActionStrip *strip;
+
+ if (LICENSE_KEY_VALID){
+ for (base=G.scene->base.first; base; base=base->next){
+ if (nla_filter(base, 0) && base->object->type==OB_ARMATURE){
+ for (strip=base->object->nlastrips.first; strip; strip=strip->next){
+ if (strip->flag & ACTSTRIP_SELECT)
+ return strip;
+ }
+ }
+ }
+
+ return NULL;
+ }
+ else
+ return NULL;
+}
+
+void clever_numbuts_nla(void){
+ bActionStrip *strip;
+ int but=0;
+ if (LICENSE_KEY_VALID){
+
+ /* Determine if an nla strip has been selected */
+ strip = get_active_nlastrip();
+ if (!strip)
+ return;
+
+ add_numbut(but++, LABEL, "Timeline Range:", 1.0, 18000.0, 0, 0);
+ add_numbut(but++, NUM|FLO, "Strip Start:", 1.0, 18000.0, &strip->start, "First frame in the timeline");
+ add_numbut(but++, NUM|FLO, "Strip End:", 1.0, 18000.0, &strip->end, "Last frame in the timeline");
+ add_numbut(but++, LABEL, "Action Range:", 1.0, 18000.0, 0, 0);
+ add_numbut(but++, NUM|FLO, "Action Start:", 1.0, 18000.0, &strip->actstart, "First frame of the action to map to the playrange");
+ add_numbut(but++, NUM|FLO, "Action End:", 1.0, 18000.0, &strip->actend, "Last frame of the action to map to the playrange");
+ add_numbut(but++, LABEL, "Blending:", 1.0, 18000.0, 0, 0);
+ add_numbut(but++, NUM|FLO, "Blendin:", 0.0, 18000.0, &strip->blendin, "Number of frames of ease-in");
+ add_numbut(but++, NUM|FLO, "Blendout:", 0.0, 18000.0, &strip->blendout, "Number of frames of ease-out");
+ add_numbut(but++, LABEL, "Options:", 1.0, 18000.0, 0, 0);
+ add_numbut(but++, NUM|FLO, "Repeat:", 0.0001, 18000.0, &strip->repeat, "Number of times the action should repeat");
+ add_numbut(but++, NUM|FLO, "Stride:", 0.0001, 1000.0, &strip->stridelen, "Distance covered by one complete cycle of the action specified in the Action Range");
+ {
+ /* STUPID HACK BECAUSE NUMBUTS ARE BROKEN WITH MULTIPLE TOGGLES */
+ short hold= (strip->flag & ACTSTRIP_HOLDLASTFRAME) ? 1 : 0;
+ short frompath=(strip->flag & ACTSTRIP_USESTRIDE) ? 1 : 0;
+
+ add_numbut(but++, TOG|SHO, "Use Path", 0, 0, &frompath, "Plays action based on position on path & stride length. Only valid for armatures that are parented to a path");
+ add_numbut(but++, TOG|SHO, "Hold", 0, 0, &hold, "Toggles whether or not to continue displaying the last frame past the end of the strip");
+ add_numbut(but++, TOG|SHO, "Add", 0, 0, &strip->mode, "Toggles additive blending mode");
+
+ do_clever_numbuts("Action", but, REDRAW);
+
+ /* STUPID HACK BECAUSE NUMBUTS ARE BROKEN WITH MULTIPLE TOGGLES */
+ if (hold) strip->flag |= ACTSTRIP_HOLDLASTFRAME;
+ else strip->flag &= ~ACTSTRIP_HOLDLASTFRAME;
+
+ if (frompath) strip->flag |= ACTSTRIP_USESTRIDE;
+ else strip->flag &= ~ACTSTRIP_USESTRIDE;
+
+ }
+
+ if (strip->end<strip->start)
+ strip->end=strip->start;
+
+
+ if (strip->blendin>(strip->end-strip->start))
+ strip->blendin = strip->end-strip->start;
+
+ if (strip->blendout>(strip->end-strip->start))
+ strip->blendout = strip->end-strip->start;
+
+ if (strip->blendin > (strip->end-strip->start-strip->blendout))
+ strip->blendin = (strip->end-strip->start-strip->blendout);
+
+ if (strip->blendout > (strip->end-strip->start-strip->blendin))
+ strip->blendout = (strip->end-strip->start-strip->blendin);
+
+
+ update_for_newframe();
+ allqueue (REDRAWNLA, 0);
+ allqueue (REDRAWVIEW3D, 0);
+ }
+}
+
+static void deselect_nlachannels(int test){
+ int sel = 1;
+ Base *base;
+ bConstraintChannel *conchan;
+
+ if (test){
+ for (base=G.scene->base.first; base; base=base->next){
+ /* Check base flags for previous selection */
+ if (base->flag & SELECT){
+ sel=0;
+ break;
+ }
+
+ /* Check constraint flags for previous selection */
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
+ if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
+ sel=0;
+ base = G.scene->base.last;
+ break;
+ }
+ }
+ }
+ }
+ else
+ sel = 0;
+
+ /* Select objects */
+ for (base=G.scene->base.first; base; base=base->next){
+ if (sel){
+ if (nla_filter(base, 0))
+ base->flag |= SELECT;
+ }
+ else
+ base->flag &= ~SELECT;
+
+ /* Select constraint channels */
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
+ if (sel){
+ if (nla_filter(base, 0))
+ conchan->flag |= CONSTRAINT_CHANNEL_SELECT;
+ }
+ else
+ conchan->flag &= ~CONSTRAINT_CHANNEL_SELECT;
+ }
+ }
+}
+
+static void delete_nlachannels(void){
+ Base *base;
+ bConstraintChannel *conchan, *nextchan;
+ int sel=0;
+
+ /* See if there is anything selected */
+ for (base = G.scene->base.first; base && (!sel); base=base->next){
+ /* Check constraints */
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
+ if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
+ sel = 1;
+ break;
+ }
+ }
+ }
+
+ if (!sel)
+ return;
+
+ if (okee ("Delete selected channels")){
+ for (base=G.scene->base.first; base; base=base->next){
+ for (conchan=base->object->constraintChannels.first; conchan; conchan=nextchan){
+ nextchan = conchan->next;
+
+ if (conchan->flag & CONSTRAINT_CHANNEL_SELECT){
+ /* If we're the active constraint, unlink us */
+ if (conchan==base->object->activecon)
+ base->object->activecon = NULL;
+
+ if (conchan->ipo)
+ conchan->ipo->id.us--;
+ BLI_freelinkN(&base->object->constraintChannels, conchan);
+ }
+ }
+ }
+ }
+} \ No newline at end of file