This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/src/editnla.c
Joshua Leung 188e3ede4f == NLA/IPO Muting ==
This commit adds a few open/closed 'eye' icons to the NLA editor to toggle IPO-block muting on Object (IPO) channels, and Action Strip muting on Action Strips, like in the Action Editor.
2007-06-22 11:55:00 +00:00

2297 lines
56 KiB
C

/**
* $Id$
*
* ***** BEGIN GPL 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.
*
* 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 *****
*
* 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 "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "DNA_action_types.h"
#include "DNA_constraint_types.h"
#include "DNA_curve_types.h"
#include "DNA_ipo_types.h"
#include "DNA_object_types.h"
#include "DNA_nla_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
#include "BKE_action.h"
#include "BKE_blender.h"
#include "BKE_depsgraph.h"
#include "BKE_group.h"
#include "BKE_global.h"
#include "BKE_ipo.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_nla.h"
#include "BKE_utildefines.h"
#include "BIF_screen.h"
#include "BIF_interface.h"
#include "BIF_butspace.h"
#include "BIF_space.h"
#include "BIF_mywindow.h"
#include "BIF_editview.h"
#include "BIF_toolbox.h"
#include "BIF_editnla.h"
#include "BIF_editaction.h"
#include "BSE_editipo.h"
#include "BSE_editnla_types.h"
#include "BSE_headerbuttons.h"
#include "BSE_drawipo.h"
#include "BSE_editaction_types.h"
#include "BSE_trans_types.h"
#include "BSE_edit.h"
#include "BSE_filesel.h"
#include "BDR_editobject.h"
#include "BSE_drawnla.h"
#include "BSE_time.h"
#include "blendef.h"
#include "mydevice.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
/* Note: A lot of these pretty much duplicate the behaviour of the
action windows. The functions should be shared, not copy-pasted */
static void mouse_nla(int selectmode);
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]);
/* ******************** SPACE: NLA ********************** */
void shift_nlastrips_up(void) {
Base *base;
bActionStrip *strip, *prevstrip;
for (base=G.scene->base.first; base; base=base->next) {
if (base->object->nlaflag & OB_NLA_COLLAPSED)
continue;
for (strip = base->object->nlastrips.first;
strip; strip=strip->next){
if (strip->flag & ACTSTRIP_SELECT) {
if ( (prevstrip = strip->prev) ) {
if (prevstrip->prev)
prevstrip->prev->next = strip;
if (strip->next)
strip->next->prev = prevstrip;
strip->prev = prevstrip->prev;
prevstrip->next = strip->next;
strip->next = prevstrip;
prevstrip->prev = strip;
if (prevstrip == base->object->nlastrips.first)
base->object->nlastrips.first = strip;
if (strip == base->object->nlastrips.last)
base->object->nlastrips.last = prevstrip;
strip = prevstrip;
}
else {
break;
}
}
}
}
BIF_undo_push("Shift NLA strip");
allqueue (REDRAWNLA, 0);
}
void shift_nlastrips_down(void) {
Base *base;
bActionStrip *strip, *nextstrip;
for (base=G.scene->base.first; base; base=base->next) {
if (base->object->nlaflag & OB_NLA_COLLAPSED)
continue;
for (strip = base->object->nlastrips.last;
strip; strip=strip->prev){
if (strip->flag & ACTSTRIP_SELECT) {
if ( (nextstrip = strip->next) ) {
if (nextstrip->next)
nextstrip->next->prev = strip;
if (strip->prev)
strip->prev->next = nextstrip;
strip->next = nextstrip->next;
nextstrip->prev = strip->prev;
strip->prev = nextstrip;
nextstrip->next = strip;
if (nextstrip == base->object->nlastrips.last)
base->object->nlastrips.last = strip;
if (strip == base->object->nlastrips.first)
base->object->nlastrips.first = nextstrip;
strip = nextstrip;
}
else {
break;
}
}
}
}
BIF_undo_push("Shift NLA strips");
allqueue (REDRAWNLA, 0);
}
void synchronize_action_strips(void)
{
Base *base;
bActionStrip *strip;
for (base=G.scene->base.first; base; base=base->next) {
/* step 1: adjust strip-lengths */
for (strip = base->object->nlastrips.last; strip; strip=strip->prev) {
if (strip->flag & ACTSTRIP_LOCK_ACTION) {
float actstart, actend;
calc_action_range(strip->act, &actstart, &actend, 1);
if(strip->actstart!=actstart || strip->actend!=actend) {
float mapping= (strip->end - strip->start)/(strip->actend - strip->actstart);
strip->start+= mapping*(actstart - strip->actstart);
strip->end+= mapping*(actend - strip->actend);
strip->actstart= actstart;
strip->actend= actend;
}
}
}
/* step 2: adjust blendin/out values for each strip if option is turned on */
for (strip= base->object->nlastrips.first; strip; strip=strip->next) {
if (strip->flag & ACTSTRIP_AUTO_BLENDS) {
bActionStrip *prev= strip->prev;
bActionStrip *next= strip->next;
float pr[2], nr[2];
strip->blendin = 0.0f;
strip->blendout = 0.0f;
/* setup test ranges */
if (prev && next) {
/* init range for previous strip */
pr[0]= prev->start;
pr[1]= prev->end;
/* init range for next strip */
nr[0]= next->start;
nr[1]= next->end;
}
else if (prev) {
/* next strip's range is same as previous strip's range */
pr[0] = nr[0] = prev->start;
pr[1] = nr[1] = prev->end;
}
else if (next) {
/* previous strip's range is same as next strip's range */
pr[0] = nr[0] = next->start;
pr[1] = nr[1] = next->end;
}
else {
/* there shouldn't be any more strips to loop through for this operation */
break;
}
/* test various cases */
if ( IN_RANGE(pr[1], strip->start, strip->end) &&
(IN_RANGE(pr[0], strip->start, strip->end)==0) )
{
/* previous strip intersects start of current */
if ( IN_RANGE(nr[1], strip->start, strip->end) &&
(IN_RANGE(nr[0], strip->start, strip->end)==0) )
{
/* next strip also intersects start of current */
if (nr[1] < pr[1])
strip->blendin= nr[1] - strip->start;
else
strip->blendin= pr[1] - strip->start;
}
else if (IN_RANGE(nr[0], strip->start, strip->end) &&
(IN_RANGE(nr[1], strip->start, strip->end)==0))
{
/* next strip intersects end of current */
strip->blendout= strip->end - nr[0];
strip->blendin= pr[1] - strip->start;
}
else {
/* only previous strip intersects current */
strip->blendin= pr[1] - strip->start;
}
}
else if (IN_RANGE(pr[0], strip->start, strip->end) &&
(IN_RANGE(pr[1], strip->start, strip->end)==0) )
{
/* previous strip intersects end of current */
if ( IN_RANGE(nr[0], strip->start, strip->end) &&
(IN_RANGE(nr[1], strip->start, strip->end)==0) )
{
/* next strip also intersects end of current */
if (nr[1] > pr[1])
strip->blendout= strip->end - nr[0];
else
strip->blendout= strip->end - pr[0];
}
else if (IN_RANGE(nr[1], strip->start, strip->end) &&
(IN_RANGE(nr[0], strip->start, strip->end)==0))
{
/* next strip intersects start of current */
strip->blendin= nr[1] - strip->start;
strip->blendout= strip->end - pr[0];
}
else {
/* only previous strip intersects current */
strip->blendout= strip->end - pr[0];
}
}
else if (IN_RANGE(nr[1], strip->start, strip->end) &&
(IN_RANGE(nr[0], strip->start, strip->end)==0) )
{
/* next strip intersects start of current */
if ( IN_RANGE(pr[1], strip->start, strip->end) &&
(IN_RANGE(pr[0], strip->start, strip->end)==0) )
{
/* previous strip also intersects start of current */
if (pr[1] < nr[1])
strip->blendin= pr[1] - strip->start;
else
strip->blendin= nr[1] - strip->start;
}
else if (IN_RANGE(pr[0], strip->start, strip->end) &&
(IN_RANGE(pr[1], strip->start, strip->end)==0))
{
/* previous strip intersects end of current */
strip->blendout= strip->end - pr[0];
strip->blendin= nr[1] - strip->start;
}
else {
/* only next strip intersects current */
strip->blendin= nr[1] - strip->start;
}
}
else if (IN_RANGE(nr[0], strip->start, strip->end) &&
(IN_RANGE(nr[1], strip->start, strip->end)==0) )
{
/* next strip intersects end of current */
if ( IN_RANGE(pr[0], strip->start, strip->end) &&
(IN_RANGE(pr[1], strip->start, strip->end)==0) )
{
/* previous strip also intersects end of current */
if (pr[1] > nr[1])
strip->blendout= strip->end - pr[0];
else
strip->blendout= strip->end - nr[0];
}
else if (IN_RANGE(pr[1], strip->start, strip->end) &&
(IN_RANGE(pr[0], strip->start, strip->end)==0))
{
/* previous strip intersects start of current */
strip->blendin= pr[1] - strip->start;
strip->blendout= strip->end - nr[0];
}
else {
/* only next strip intersects current */
strip->blendout= strip->end - nr[0];
}
}
/* make sure blending stays in ranges */
CLAMP(strip->blendin, 0, (strip->end-strip->start));
CLAMP(strip->blendout, 0, (strip->end-strip->start));
}
}
}
}
void reset_action_strips(int val)
{
Base *base;
bActionStrip *strip;
for (base=G.scene->base.first; base; base=base->next) {
if (base->object->nlaflag & OB_NLA_COLLAPSED)
continue;
for (strip = base->object->nlastrips.last; strip; strip=strip->prev) {
if (strip->flag & ACTSTRIP_SELECT) {
if(val==2) {
calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
}
else if(val==1) {
float mapping= (strip->actend - strip->actstart)/(strip->end - strip->start);
strip->end= strip->start + mapping*(strip->end - strip->start);
}
base->object->ctime= -1234567.0f; // eveil!
DAG_object_flush_update(G.scene, base->object, OB_RECALC_OB|OB_RECALC_DATA);
}
}
}
BIF_undo_push("Reset NLA strips");
allqueue (REDRAWVIEW3D, 0);
allqueue (REDRAWACTION, 0);
allqueue (REDRAWNLA, 0);
}
void snap_action_strips(int snap_mode)
{
Base *base;
bActionStrip *strip;
for (base=G.scene->base.first; base; base=base->next) {
/* object has ipo - these keyframes should be able to be snapped, even if strips are collapsed */
if (base->object->ipo) {
snap_ipo_keys(base->object->ipo, snap_mode);
}
/* object is collapsed - action and nla strips not shown/editable */
if (base->object->nlaflag & OB_NLA_COLLAPSED)
continue;
/* snap action strips */
for (strip = base->object->nlastrips.last; strip; strip=strip->prev) {
if (strip->flag & ACTSTRIP_SELECT) {
if (snap_mode==1) {
/* nearest frame */
strip->start= floor(strip->start+0.5);
strip->end= floor(strip->end+0.5);
}
else if (snap_mode==2) {
/* current frame */
float diff;
if (CFRA < strip->start) {
diff = (strip->start - CFRA);
strip->start -= diff;
strip->end -= diff;
}
else {
diff = (CFRA - strip->start);
strip->start += diff;
strip->end += diff;
}
}
}
}
/* object has action */
if (base->object->action) {
ListBase act_data = {NULL, NULL};
bActListElem *ale;
int filter;
/* filter action data */
filter= (ACTFILTER_VISIBLE | ACTFILTER_FOREDIT | ACTFILTER_IPOKEYS);
actdata_filter(&act_data, filter, base->object->action, ACTCONT_ACTION);
/* snap to frame */
for (ale= act_data.first; ale; ale= ale->next) {
actstrip_map_ipo_keys(base->object, ale->key_data, 0, 1);
snap_ipo_keys(ale->key_data, snap_mode);
actstrip_map_ipo_keys(base->object, ale->key_data, 1, 1);
}
BLI_freelistN(&act_data);
remake_action_ipos(base->object->action);
}
}
BIF_undo_push("Snap NLA strips");
allqueue (REDRAWVIEW3D, 0);
allqueue (REMAKEIPO, 0);
allqueue (REDRAWIPO, 0);
allqueue (REDRAWACTION, 0);
allqueue (REDRAWNLA, 0);
}
static void set_active_strip(Object *ob, bActionStrip *act)
{
bActionStrip *strip;
for (strip = ob->nlastrips.first; strip; strip=strip->next)
strip->flag &= ~ACTSTRIP_ACTIVE;
if(act) {
act->flag |= ACTSTRIP_ACTIVE;
if(ob->action!=act->act) {
if(ob->action) ob->action->id.us--;
if(act->act->id.lib) {
ob->action= NULL;
}
else {
ob->action= act->act;
id_us_plus(&ob->action->id);
}
allqueue(REDRAWIPO, 0);
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWNLA, 0);
ob->ctime= -1234567.0f; // eveil!
DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
}
}
}
void convert_nla(void)
{
bActionStrip *strip;
Object *ob= OBACT;
char str[128];
short event;
if ((ob==NULL)||(ob->action==NULL)) {
error("Need active Object to convert Action to NLA Strip");
return;
}
sprintf(str, "Convert Action%%t|%s to NLA Strip%%x1", ob->action->id.name+2);
event = pupmenu(str);
if (event==1) {
if (ob->action) {
deselect_nlachannel_keys(0);
strip = convert_action_to_strip(ob); //creates a new NLA strip from the action in given object
set_active_strip(ob, strip);
BIF_undo_push("Convert NLA");
allqueue (REDRAWNLA, 0);
}
}
}
static void add_nla_block(short event)
{
Object *ob= OBACT;
bAction *act=NULL;
bActionStrip *strip;
int cur;
if (event!=-1){
for (cur = 1, act=G.main->action.first; act; act=act->id.next, cur++){
if (cur==event){
break;
}
}
}
/* 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;
id_us_plus(&act->id);
calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
strip->start = G.scene->r.cfra; /* could be mval[0] another time... */
strip->end = strip->start + (strip->actend-strip->actstart);
/* simple prevention of zero strips */
if(strip->start>strip->end-2)
strip->end= strip->start+100;
strip->repeat = 1.0;
strip->flag = ACTSTRIP_SELECT|ACTSTRIP_LOCK_ACTION;
find_stridechannel(ob, strip);
set_active_strip(ob, strip);
strip->object= group_get_member_with_action(ob->dup_group, act);
if(strip->object)
id_lib_extern(&strip->object->id); /* checks lib data, sets correct flag for saving then */
if(ob->nlastrips.first == NULL)
ob->nlaflag |= OB_NLA_OVERRIDE;
BLI_addtail(&ob->nlastrips, strip);
BIF_undo_push("Add NLA strip");
}
static void add_nla_block_by_name(char name[32], Object *ob, short hold, short add, float repeat)
{
bAction *act=NULL;
bActionStrip *strip;
int cur;
if (name){
for (cur = 1, act=G.main->action.first; act; act=act->id.next, cur++){
if (strcmp(name,act->id.name)==0) {
break;
}
}
}
/* 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;
calc_action_range(strip->act, &strip->actstart, &strip->actend, 1);
strip->start = G.scene->r.cfra; /* could be mval[0] another time... */
strip->end = strip->start + (strip->actend-strip->actstart);
/* simple prevention of zero strips */
if(strip->start>strip->end-2)
strip->end= strip->start+100;
strip->flag = ACTSTRIP_SELECT|ACTSTRIP_LOCK_ACTION; //|ACTSTRIP_USEMATCH;
if (hold==1)
strip->flag = strip->flag|ACTSTRIP_HOLDLASTFRAME;
if (add==1)
strip->mode = ACTSTRIPMODE_ADD;
find_stridechannel(ob, strip);
set_active_strip(ob, strip);
strip->repeat = repeat;
act->id.us++;
if(ob->nlastrips.first == NULL)
ob->nlaflag |= OB_NLA_OVERRIDE;
BLI_addtail(&ob->nlastrips, strip);
}
static void add_nla_databrowse_callback(unsigned short val)
{
/* val is not used, databrowse needs it to optional pass an event */
short event;
if(OBACT==NULL) return;
event= G.snla->menunr; /* set by databrowse or pupmenu */
add_nla_block(event);
}
/* Adds strip to to active Object */
void add_nlablock(void)
{
Object *ob= OBACT;
short event;
short nr=0;
char *str, title[64];
if(ob==NULL) {
error("Need active Object to add NLA strips");
return;
}
sprintf(title, "Add Action strip to: %s", ob->id.name+2);
/* Popup action menu */
IDnames_to_pupstring(&str, title, NULL, &G.main->action, (ID *)G.scene, &nr);
if(nr==-2) {
MEM_freeN(str);
activate_databrowse((ID *)NULL, ID_AC, 0, 0, &G.snla->menunr,
add_nla_databrowse_callback );
return;
}
else {
event = pupmenu_col(str, 20);
MEM_freeN(str);
add_nla_block(event);
}
}
/* Creates a new action, and makes a new actionstrip of that */
void add_empty_nlablock(void)
{
Object *ob= OBACT;
bAction *act= NULL;
bActionStrip *strip;
/* check for active object first - will add strip to active object */
if (ob == NULL)
return;
/* make new action */
if ((ob->type == OB_ARMATURE) && (ob->flag & OB_POSEMODE))
act= add_empty_action("ObAction");
else
act= add_empty_action("Action");
/* make a new strip for it */
add_nla_block_by_name(act->id.name, ob, 0, 1, 1.0f);
strip= ob->nlastrips.last;
/* change some settings of the strip - try to avoid bad scaling */
if ((EFRA-CFRA) < 100) {
strip->flag |= ACTSTRIP_AUTO_BLENDS;
strip->flag &= ~ACTSTRIP_LOCK_ACTION;
strip->actstart = CFRA;
strip->actend = CFRA + 100;
strip->start = CFRA;
strip->end = CFRA + 100;
}
else {
strip->flag |= ACTSTRIP_AUTO_BLENDS;
strip->flag &= ~ACTSTRIP_LOCK_ACTION;
strip->actstart = CFRA;
strip->actend = EFRA;
strip->start = CFRA;
strip->end = EFRA;
}
BIF_undo_push("Add NLA strip");
}
/* Adds strip to to active Object */
static void relink_active_strip(void)
{
Object *ob= OBACT;
bActionStrip *strip;
bAction *act;
short event;
short cur;
char *str;
if(ob==NULL) return;
if(ob->nlaflag & OB_NLA_COLLAPSED) return;
for (strip = ob->nlastrips.first; strip; strip=strip->next)
if(strip->flag & ACTSTRIP_ACTIVE)
break;
if(strip==NULL) return;
/* Popup action menu */
IDnames_to_pupstring(&str, "Relink Action strip", NULL, &G.main->action, (ID *)G.scene, NULL);
if(str) {
event = pupmenu_col(str, 20);
MEM_freeN(str);
for (cur = 1, act=G.main->action.first; act; act=act->id.next, cur++){
if (cur==event){
break;
}
}
if(act) {
if(strip->act) strip->act->id.us--;
strip->act = act;
id_us_plus(&act->id);
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWNLA, 0);
}
}
}
/* Left hand side of channels display, selects objects */
static void mouse_nlachannels(short mval[2])
{
bActionStrip *strip= NULL;
Base *base;
Object *ob=NULL;
float x,y;
int click, obclick=0, actclick=0;
int wsize;
wsize = (count_nla_levels ()*(NLACHANNELHEIGHT+NLACHANNELSKIP));
wsize+= NLACHANNELHEIGHT/2;
areamouseco_to_ipoco(G.v2d, mval, &x, &y);
click = (int)floor( ((float)wsize - y) / (NLACHANNELHEIGHT+NLACHANNELSKIP));
if (click<0)
return;
for (base = G.scene->base.first; base; base=base->next){
if (nla_filter(base)) {
ob= base->object;
/* See if this is a base selected */
if (click==0) {
obclick= 1;
break;
}
click--;
/* see if any strips under object */
if ((ob->nlaflag & OB_NLA_COLLAPSED)==0) {
/* See if this is an action */
if (ob->action){
if (click==0) {
actclick= 1;
break;
}
click--;
}
/* See if this is an nla strip */
if(ob->nlastrips.first) {
for (strip = ob->nlastrips.first; strip; strip=strip->next){
if (click==0) break;
click--;
}
if (strip && click==0) break;
}
}
}
}
if (!base)
return;
/* Handle object strip selection */
if (G.qual & LR_SHIFTKEY) {
if (base->flag & SELECT) base->flag &= ~SELECT;
else base->flag |= SELECT;
}
else {
deselect_nlachannels (0); // Auto clear
base->flag |= SELECT;
}
ob->flag= base->flag;
if(base!=BASACT) set_active_base(base);
if(actclick) /* de-activate all strips */
set_active_strip(ob, NULL);
else if(strip) {
if(mval[0] >= (NLAWIDTH-16)) /* toggle strip muting */
strip->flag ^= ACTSTRIP_MUTE;
else /* set action */
set_active_strip(ob, strip);
}
/* icon toggles beside strip */
if (obclick && mval[0]<20) {
/* collapse option for NLA object strip */
ob->nlaflag ^= OB_NLA_COLLAPSED;
}
else if(obclick && mval[0]<36) {
/* override option for NLA */
ob->nlaflag ^= OB_NLA_OVERRIDE;
}
else if((obclick) && (ob->ipo) && (mval[0] >= (NLAWIDTH-16))) {
/* mute Object IPO-block */
ob->ipo->muteipo = (ob->ipo->muteipo)? 0: 1;
}
ob->ctime= -1234567.0f; // eveil!
DAG_object_flush_update(G.scene, ob, OB_RECALC_OB|OB_RECALC_DATA);
allqueue(REDRAWIPO, 0);
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWNLA, 0);
}
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 (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;
}
}
}
/* check if collapsed */
if (base->object->nlaflag & OB_NLA_COLLAPSED)
continue;
/* Test action ipos */
if (sel){
if (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){
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);
}
/* check if collapsed */
if (base->object->nlaflag & OB_NLA_COLLAPSED)
continue;
/* Set the action ipos */
if (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 */
for (strip=base->object->nlastrips.first; strip; strip=strip->next){
if (sel)
strip->flag |= ACTSTRIP_SELECT;
else
strip->flag &= ~ACTSTRIP_SELECT;
}
}
}
/* very bad call! */
static void recalc_all_ipos(void)
{
Ipo *ipo;
IpoCurve *icu;
/* Go to each ipo */
for (ipo=G.main->ipo.first; ipo; ipo=ipo->id.next){
for (icu = ipo->curve.first; icu; icu=icu->next){
sort_time_ipocurve(icu);
testhandles_ipocurve(icu);
}
}
}
void transform_nlachannel_keys(int mode, int dummy)
{
Base *base;
TransVert *tv;
bActionChannel *chan;
bActionStrip *strip;
bConstraintChannel *conchan;
float sval[2], cval[2], lastcval[2];
float fac=0.0F;
float deltax, startx;
int i;
int loop=1;
int tvtot=0;
int invert=0, firsttime=1;
short mvals[2], mvalc[2];
short cancel=0;
char str[256];
/* Ensure that partial selections result in beztriple selections */
for (base=G.scene->base.first; base; base=base->next){
/* Check object ipos */
i= fullselect_ipo_keys(base->object->ipo);
if(i) base->flag |= BA_HAS_RECALC_OB;
tvtot+=i;
/* Check object constraint ipos */
for(conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
tvtot+=fullselect_ipo_keys(conchan->ipo);
/* skip actions and nlastrips if object is collapsed */
if (base->object->nlaflag & OB_NLA_COLLAPSED)
continue;
/* Check action ipos */
if (base->object->action){
/* exclude if strip is selected too */
for (strip=base->object->nlastrips.first; strip; strip=strip->next) {
if (strip->flag & ACTSTRIP_SELECT)
if(strip->act==base->object->action)
break;
}
if(strip==NULL) {
for (chan=base->object->action->chanbase.first; chan; chan=chan->next) {
if (EDITABLE_ACHAN(chan)) {
i= fullselect_ipo_keys(chan->ipo);
if(i) base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA;
tvtot+=i;
/* Check action constraint ipos */
if (EXPANDED_ACHAN(chan) && FILTER_CON_ACHAN(chan)) {
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) {
if (EDITABLE_CONCHAN(conchan))
tvtot+=fullselect_ipo_keys(conchan->ipo);
}
}
}
}
}
}
/* Check nlastrips */
for (strip=base->object->nlastrips.first; strip; strip=strip->next){
if (strip->flag & ACTSTRIP_SELECT) {
base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA;
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);
/* skip actions and nlastrips if object collapsed */
if (base->object->nlaflag & OB_NLA_COLLAPSED)
continue;
/* Manipulate action ipos */
if (base->object->action){
/* exclude if strip is selected too */
for (strip=base->object->nlastrips.first; strip; strip=strip->next){
if (strip->flag & ACTSTRIP_SELECT)
if(strip->act==base->object->action)
break;
}
/* can include - no selected strip is action */
if(strip==NULL) {
for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
if (EDITABLE_ACHAN(chan)) {
tvtot=add_trans_ipo_keys(chan->ipo, tv, tvtot);
/* Manipulate action constraint ipos */
if (EXPANDED_ACHAN(chan) && FILTER_CON_ACHAN(chan)) {
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) {
if (EDITABLE_CONCHAN(conchan))
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(10);
}
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 & USER_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 & USER_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, "scaleX: %.3f", fac);
headerprint(str);
}
else if (mode=='g'){
sprintf(str, "deltaX: %.3f", fac);
headerprint(str);
}
if (G.snla->lock) {
for (base=G.scene->base.first; base; base=base->next){
if(base->flag & BA_HAS_RECALC_OB)
base->object->recalc |= OB_RECALC_OB;
if(base->flag & BA_HAS_RECALC_DATA)
base->object->recalc |= OB_RECALC_DATA;
if(base->object->recalc) base->object->ctime= -1234567.0f; // eveil!
}
DAG_scene_flush_update(G.scene, screen_view3d_layers());
force_draw_all(0);
}
else {
force_draw(0);
}
}
}
lastcval[0]= cval[0];
lastcval[1]= cval[1];
firsttime= 0;
}
synchronize_action_strips();
/* cleanup */
for (base=G.scene->base.first; base; base=base->next)
base->flag &= ~(BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA);
if(cancel==0) BIF_undo_push("Select all NLA");
recalc_all_ipos(); // bad
allqueue (REDRAWVIEW3D, 0);
allqueue (REDRAWNLA, 0);
allqueue (REDRAWIPO, 0);
MEM_freeN (tv);
}
void delete_nlachannel_keys(void)
{
Base *base;
bActionChannel *chan;
bConstraintChannel *conchan;
bActionStrip *strip, *nextstrip;
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);
/* skip actions and nlastrips if object collapsed */
if (base->object->nlaflag & OB_NLA_COLLAPSED)
continue;
/* Delete NLA strips */
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->action){
for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
if (EDITABLE_ACHAN(chan))
delete_ipo_keys(chan->ipo);
/* Delete action constraint keys */
for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
if (EDITABLE_CONCHAN(conchan))
delete_ipo_keys(conchan->ipo);
}
}
}
}
recalc_all_ipos(); // bad
synchronize_action_strips();
BIF_undo_push("Delete NLA keys");
allspace(REMAKEIPO,0);
allqueue (REDRAWVIEW3D, 0);
allqueue(REDRAWNLA, 0);
allqueue(REDRAWIPO, 0);
}
void duplicate_nlachannel_keys(void)
{
Base *base;
bActionChannel *chan;
bConstraintChannel *conchan;
bActionStrip *strip, *laststrip;
/* 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);
/* skip actions and nlastrips if object collapsed */
if (base->object->nlaflag & OB_NLA_COLLAPSED)
continue;
/* Duplicate nla strips */
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;
set_active_strip(base->object, newstrip);
}
if (strip==laststrip)
break;
}
/* Duplicate actionchannel keys */
if (base->object->action){
for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
if (EDITABLE_ACHAN(chan))
duplicate_ipo_keys(chan->ipo);
/* Duplicate action constraint keys */
for(conchan=chan->constraintChannels.first; conchan; conchan=conchan->next) {
if (EDITABLE_CONCHAN(conchan))
duplicate_ipo_keys(conchan->ipo);
}
}
}
}
BIF_undo_push("Duplicate NLA");
transform_nlachannel_keys ('g', 0);
}
void borderselect_nla(void)
{
Base *base;
rcti rect;
rctf rectf;
int val, selectmode;
short mval[2];
float ymin, ymax;
bActionStrip *strip;
bConstraintChannel *conchan;
if ( (val = get_border (&rect, 3)) ){
if (val == LEFTMOUSE)
selectmode = SELECT_ADD;
else
selectmode = SELECT_SUBTRACT;
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);
ymax+= (NLACHANNELHEIGHT+NLACHANNELSKIP)/2;
for (base=G.scene->base.first; base; base=base->next){
if (nla_filter(base)) {
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
/* Check object ipos */
if (base->object->ipo){
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
borderselect_ipo_key(base->object->ipo, rectf.xmin, rectf.xmax,
selectmode);
}
/* Check object constraint ipos */
for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax)))
borderselect_ipo_key(conchan->ipo, rectf.xmin, rectf.xmax,
selectmode);
}
ymax=ymin;
/* skip actions and nlastrips if object collapsed */
if (base->object->nlaflag & OB_NLA_COLLAPSED)
continue;
/* Check action ipos */
if (base->object->action){
bActionChannel *chan;
float xmin, xmax;
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
/* if action is mapped in NLA, it returns a correction */
xmin= get_action_frame(base->object, rectf.xmin);
xmax= get_action_frame(base->object, rectf.xmax);
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
for (chan=base->object->action->chanbase.first; chan; chan=chan->next){
borderselect_ipo_key(chan->ipo, xmin, xmax, selectmode);
/* Check action constraint ipos */
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
borderselect_ipo_key(conchan->ipo, xmin, xmax, selectmode);
}
}
ymax=ymin;
} /* End of if action */
/* Skip nlastrips */
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;
}
}
}
BIF_undo_push("Border select NLA");
allqueue(REDRAWTIME, 0);
allqueue(REDRAWIPO, 0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWNLA, 0);
allqueue(REDRAWSOUND, 0);
}
}
/* right hand side of window, does ipokeys, actionkeys or strips */
static void mouse_nla(int selectmode)
{
Base *base;
bAction *act;
bActionChannel *chan;
bActionStrip *rstrip;
bConstraintChannel *conchan;
TimeMarker *marker;
float selx;
short mval[2];
short sel, isdone=0;
getmouseco_areawin (mval);
/* Try object ipo or ob-constraint ipo selection */
base= get_nearest_nlachannel_ob_key(&selx, &sel);
marker=find_nearest_marker(1);
if (base) {
isdone= 1;
if (selectmode == SELECT_REPLACE){
deselect_nlachannel_keys(0);
selectmode = SELECT_ADD;
}
select_ipo_key(base->object->ipo, selx, selectmode);
/* Try object constraint selection */
for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
select_ipo_key(conchan->ipo, selx, selectmode);
}
else if (marker) {
/* marker */
if (selectmode == SELECT_REPLACE) {
deselect_markers(0, 0);
marker->flag |= SELECT;
}
else if (selectmode == SELECT_INVERT) {
if (marker->flag & SELECT)
marker->flag &= ~SELECT;
else
marker->flag |= SELECT;
}
else if (selectmode == SELECT_ADD)
marker->flag |= SELECT;
else if (selectmode == SELECT_SUBTRACT)
marker->flag &= ~SELECT;
std_rmouse_transform(transform_markers);
allqueue(REDRAWTIME, 0);
allqueue(REDRAWIPO, 0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWNLA, 0);
allqueue(REDRAWSOUND, 0);
}
else {
/* Try action ipo selection */
act= get_nearest_nlachannel_ac_key(&selx, &sel);
if (act) {
isdone= 1;
if (selectmode == SELECT_REPLACE){
deselect_nlachannel_keys(0);
selectmode = SELECT_ADD;
}
for (chan=act->chanbase.first; chan; chan=chan->next) {
select_ipo_key(chan->ipo, selx, selectmode);
/* Try action constraint selection */
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next)
select_ipo_key(conchan->ipo, selx, selectmode);
}
}
else {
/* Try nla strip selection */
base= get_nearest_nlastrip(&rstrip, &sel);
if (base){
isdone= 1;
if (!(G.qual & LR_SHIFTKEY)){
deselect_nlachannel_keys(0);
sel = 0;
}
if (sel)
rstrip->flag &= ~ACTSTRIP_SELECT;
else
rstrip->flag |= ACTSTRIP_SELECT;
set_active_strip(base->object, rstrip);
if(base!=BASACT) set_active_base(base);
}
}
}
if(isdone) {
std_rmouse_transform(transform_nlachannel_keys);
allqueue(REDRAWIPO, 0);
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWNLA, 0);
}
}
/* 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 */
static Base *get_nearest_nlastrip (bActionStrip **rstrip, short *sel)
{
Base *base, *firstbase=NULL;
bActionStrip *strip, *firststrip=NULL, *foundstrip=NULL;
rctf rectf;
float ymin, ymax;
short mval[2];
short foundsel = 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);
ymax+= NLACHANNELHEIGHT/2;
for (base = G.scene->base.first; base; base=base->next){
if (nla_filter(base)) {
/* Skip object ipos */
ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
/* check if skip strips if collapsed */
if (base->object->nlaflag & OB_NLA_COLLAPSED)
continue;
/* Skip action ipos */
if (base->object->action)
ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
/* the strips */
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;
}
static Base *get_nearest_nlachannel_ob_key (float *index, short *sel)
{
Base *base;
IpoCurve *icu;
Base *firstbase=NULL;
bConstraintChannel *conchan;
int foundsel=0;
float firstvertx=-1, foundx=-1;
int i;
short mval[2];
float ymin, ymax;
rctf rectf;
*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);
ymax+= NLACHANNELHEIGHT/2;
*sel=0;
for (base=G.scene->base.first; base; base=base->next){
if (nla_filter(base)) {
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
/* Handle object ipo selection */
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;
firstvertx=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;
}
}
}
}
}
}
/* Handle object constraint ipos */
for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next){
if ( !((ymax < rectf.ymin) || (ymin > rectf.ymax)) && conchan->ipo){
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;
firstvertx=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 actions and nlastrips if object is collapsed */
if (base->object->nlaflag & OB_NLA_COLLAPSED)
continue;
/* Skip action ipos */
if (base->object->action){
ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP);
}
/* Skip nlastrips */
ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
}
}
*index=firstvertx;
return firstbase;
}
static bAction *get_nearest_nlachannel_ac_key (float *index, short *sel)
{
Base *base;
IpoCurve *icu;
bAction *firstact=NULL;
bActionChannel *chan;
bConstraintChannel *conchan;
rctf rectf;
float firstvert=-1, foundx=-1;
float ymin, ymax, xmin, xmax;
int i;
int foundsel=0;
short mval[2];
*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);
ymax+= NLACHANNELHEIGHT/2;
*sel=0;
for (base=G.scene->base.first; base; base=base->next){
/* Handle object ipo selection */
if (nla_filter(base)) {
/* Skip object ipo and ob-constraint ipo */
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
/* skip this object if it is collapsed */
if (base->object->nlaflag & OB_NLA_COLLAPSED)
continue;
ymax=ymin;
/* Handle action ipos */
if (base->object->action){
bAction *act= base->object->action;
/* if action is mapped in NLA, it returns a correction */
xmin= get_action_frame(base->object, rectf.xmin);
xmax= get_action_frame(base->object, rectf.xmax);
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))){
for (chan=act->chanbase.first; chan; chan=chan->next){
if(chan->ipo) {
for (icu=chan->ipo->curve.first; icu; icu=icu->next){
for (i=0; i<icu->totvert; i++){
if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] <= xmax ){
if (!firstact){
firstact= act;
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 act;
}
}
}
}
}
for (conchan=chan->constraintChannels.first; conchan; conchan=conchan->next){
ymin=ymax-(NLACHANNELHEIGHT+NLACHANNELSKIP);
if ( !((ymax < rectf.ymin) || (ymin > rectf.ymax)) && conchan->ipo){
for (icu=conchan->ipo->curve.first; icu; icu=icu->next){
for (i=0; i<icu->totvert; i++){
if (icu->bezt[i].vec[1][0] > xmin && icu->bezt[i].vec[1][0] <= 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 */
ymax-=(NLACHANNELHEIGHT+NLACHANNELSKIP)*BLI_countlist(&base->object->nlastrips);
}
}
*index=firstvert;
return firstact;
}
void deselect_nlachannels(int test)
{
Base *base;
int sel = 1;
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;
}
}
}
else
sel = 0;
/* Select objects */
for (base=G.scene->base.first; base; base=base->next){
if (sel){
if (nla_filter(base))
base->flag |= SELECT;
}
else
base->flag &= ~SELECT;
base->object->flag= base->flag;
}
}
static Object *get_object_from_active_strip(void) {
Base *base;
bActionStrip *strip;
for (base=G.scene->base.first; base; base=base->next) {
if ((base->object->nlaflag & OB_NLA_COLLAPSED)==0) {
for (strip = base->object->nlastrips.first;
strip; strip=strip->next){
if (strip->flag & ACTSTRIP_SELECT) {
return base->object;
}
}
}
}
return NULL;
}
void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
{
unsigned short event= evt->event;
short val= evt->val;
SpaceNla *snla = curarea->spacedata.first;
int doredraw= 0;
short mval[2];
float dx,dy;
int cfra;
short mousebut = L_MOUSE;
Object *ob; //in shift-B / bake
if (curarea->win==0) return;
if (!snla) return;
if(val) {
if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0;
/* swap mouse buttons based on user preference */
if (U.flag & USER_LMOUSESELECT) {
if (event == LEFTMOUSE) {
event = RIGHTMOUSE;
mousebut = L_MOUSE;
} else if (event == RIGHTMOUSE) {
event = LEFTMOUSE;
mousebut = R_MOUSE;
}
}
getmouseco_areawin(mval);
switch(event) {
case UI_BUT_EVENT:
do_nlabuts(val); // in drawnla.c
break;
case HOMEKEY:
do_nla_buttons(B_NLAHOME);
break;
case EQUALKEY:
shift_nlastrips_up();
break;
case PAGEUPKEY:
if (G.qual & LR_CTRLKEY)
shift_nlastrips_up();
else {
nextprev_marker(1);
allqueue(REDRAWTIME, 0);
allqueue(REDRAWIPO, 0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWNLA, 0);
allqueue(REDRAWSOUND, 0);
}
break;
case MINUSKEY:
shift_nlastrips_down();
break;
case PAGEDOWNKEY:
if (G.qual & LR_CTRLKEY)
shift_nlastrips_down();
else {
nextprev_marker(-1);
allqueue(REDRAWTIME, 0);
allqueue(REDRAWIPO, 0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWNLA, 0);
allqueue(REDRAWSOUND, 0);
}
break;
case AKEY:
if (G.qual & LR_SHIFTKEY){
add_nlablock();
allqueue (REDRAWNLA, 0);
allqueue (REDRAWVIEW3D, 0);
}
else if (G.qual & LR_CTRLKEY) {
deselect_markers(1, 0);
allqueue(REDRAWTIME, 0);
allqueue(REDRAWIPO, 0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWNLA, 0);
allqueue(REDRAWSOUND, 0);
}
else{
if (mval[0]>=NLAWIDTH)
deselect_nlachannel_keys(1);
else{
deselect_nlachannels(1);
allqueue (REDRAWVIEW3D, 0);
}
allqueue (REDRAWNLA, 0);
allqueue (REDRAWIPO, 0);
BIF_undo_push("(De)select all NLA");
}
break;
case BKEY:
if (G.qual & LR_SHIFTKEY){
bake_all_to_action();
allqueue (REDRAWNLA, 0);
allqueue (REDRAWVIEW3D, 0);
BIF_undo_push("Bake All To Action");
ob = get_object_from_active_strip();
//build_match_caches(ob);
}
else if (G.qual & LR_CTRLKEY)
borderselect_markers();
else
borderselect_nla();
break;
case CKEY:
if(G.qual==LR_CTRLKEY) {
if(okee("Copy Modifiers"))
copy_action_modifiers();
}
else convert_nla();
break;
case DKEY:
if (G.qual == (LR_CTRLKEY|LR_SHIFTKEY) && mval[0]>=NLAWIDTH) {
duplicate_marker();
}
else if (G.qual & LR_SHIFTKEY && mval[0]>=NLAWIDTH){
duplicate_nlachannel_keys();
update_for_newframe_muted();
}
break;
case GKEY:
if (mval[0]>=NLAWIDTH) {
if (G.qual & LR_CTRLKEY) {
transform_markers('g', 0);
}
else {
transform_nlachannel_keys ('g', 0);
update_for_newframe_muted();
}
}
break;
case MKEY:
/* marker operations */
if (G.qual == 0)
add_marker(CFRA);
else if (G.qual == LR_CTRLKEY)
rename_marker();
else
break;
allqueue(REDRAWTIME, 0);
allqueue(REDRAWIPO, 0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWNLA, 0);
allqueue(REDRAWSOUND, 0);
break;
case NKEY:
if(G.qual==0) {
toggle_blockhandler(curarea, NLA_HANDLER_PROPERTIES, UI_PNL_TO_MOUSE);
scrarea_queue_winredraw(curarea);
}
else if (G.qual & LR_SHIFTKEY) {
add_empty_nlablock();
}
break;
case LKEY:
relink_active_strip();
break;
case PKEY:
if (G.qual & LR_CTRLKEY) /* set preview range */
anim_previewrange_set();
else if (G.qual & LR_ALTKEY) /* clear preview range */
anim_previewrange_clear();
allqueue(REDRAWTIME, 0);
allqueue(REDRAWBUTSALL, 0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWNLA, 0);
allqueue(REDRAWIPO, 0);
break;
case SKEY:
if(G.qual==LR_ALTKEY) {
val= pupmenu("Action Strip Scale%t|Clear Strip Scale%x1|Remap Start/End%x2");
if(val==1)
reset_action_strips(1);
else if(val==2)
reset_action_strips(2);
}
else if(G.qual & LR_SHIFTKEY) {
val= pupmenu("Snap To%t|Nearest Frame%x1|Current Frame%x2");
if (val==1 || val==2)
snap_action_strips(val);
}
else {
if (mval[0]>=NLAWIDTH)
transform_nlachannel_keys ('s', 0);
update_for_newframe_muted();
}
break;
case DELKEY:
case XKEY:
if (mval[0]>=NLAWIDTH) {
if (okee("Erase selected?")) {
delete_nlachannel_keys();
update_for_newframe_muted();
remove_marker();
allqueue(REDRAWTIME, 0);
allqueue(REDRAWIPO, 0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWNLA, 0);
allqueue(REDRAWSOUND, 0);
}
}
break;
/* LEFTMOUSE and RIGHTMOUSE event codes can be swapped above,
* based on user preference USER_LMOUSESELECT
*/
case LEFTMOUSE:
if(view2dmove(LEFTMOUSE))
break; // only checks for sliders
else if (mval[0]>=snla->v2d.mask.xmin) {
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_all(0);
}
else PIL_sleep_ms(30);
} while(get_mbut() & mousebut);
break;
}
/* else pass on! */
case RIGHTMOUSE:
if (mval[0]>=snla->v2d.mask.xmin) {
if(G.qual & LR_SHIFTKEY)
mouse_nla(SELECT_INVERT);
else
mouse_nla(SELECT_REPLACE);
}
else
mouse_nlachannels(mval);
break;
case PADPLUSKEY:
view2d_zoom(G.v2d, 0.1154, sa->winx, sa->winy);
test_view2d(G.v2d, sa->winx, sa->winy);
view2d_do_locks(curarea, V2D_LOCK_COPY);
doredraw= 1;
break;
case PADMINUS:
view2d_zoom(G.v2d, -0.15, sa->winx, sa->winy);
test_view2d(G.v2d, sa->winx, sa->winy);
view2d_do_locks(curarea, V2D_LOCK_COPY);
doredraw= 1;
break;
case MIDDLEMOUSE:
case WHEELUPMOUSE:
case WHEELDOWNMOUSE:
view2dmove(event); /* in drawipo.c */
break;
}
}
if(doredraw) scrarea_queue_winredraw(curarea);
}
void bake_all_to_action(void)
{
Object *ob;
bAction *newAction;
Ipo *ipo;
ID *id;
short hold, add;
float repeat;
/* burn object-level motion into a new action */
ob = get_object_from_active_strip();
if (ob) {
if (ob->flag&OB_ARMATURE) {
//newAction = bake_obIPO_to_action(ob);
newAction = NULL;
if (newAction) {
/* unlink the object's IPO */
ipo=ob->ipo;
if (ipo) {
id = &ipo->id;
if (id->us > 0)
id->us--;
ob->ipo = NULL;
}
/* add the new Action to NLA as a strip */
hold=1;
add=1;
repeat=1.0;
printf("about to add nla block...\n");
add_nla_block_by_name(newAction->id.name, ob, hold, add, repeat);
BIF_undo_push("Add NLA strip");
}
}
}
}
void copy_action_modifiers(void)
{
bActionStrip *strip, *actstrip;
Object *ob= OBACT;
if(ob==NULL)
return;
/* active strip */
for (actstrip=ob->nlastrips.first; actstrip; actstrip=actstrip->next)
if(actstrip->flag & ACTSTRIP_ACTIVE)
break;
if(actstrip==NULL)
return;
/* copy to selected items */
for (strip=ob->nlastrips.first; strip; strip=strip->next){
if (strip->flag & ACTSTRIP_SELECT) {
if(strip!=actstrip) {
if (strip->modifiers.first)
BLI_freelistN(&strip->modifiers);
if (actstrip->modifiers.first)
duplicatelist (&strip->modifiers, &actstrip->modifiers);
}
}
}
BIF_undo_push("Copy Action Modifiers");
allqueue(REDRAWNLA, 0);
DAG_scene_flush_update(G.scene, screen_view3d_layers());
}