diff options
16 files changed, 1784 insertions, 100 deletions
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 3765337f990..f89a1eb96b8 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -254,4 +254,39 @@ void ANIM_nla_mapping_draw(gla2DDrawInfo *di, Object *ob, short restore) } } +/* Apply/Unapply NLA mapping to all keyframes in the nominated IPO block + * - restore = whether to map points back to ipo-time + * - only_keys = whether to only adjust the location of the center point of beztriples + */ +// was called actstrip_map_ipo_keys() +void ANIM_nla_mapping_apply(Object *ob, Ipo *ipo, short restore, short only_keys) +{ + IpoCurve *icu; + BezTriple *bezt; + int a; + + if (ipo==NULL) return; + + /* loop through all ipo curves, adjusting the times of the selected keys */ + for (icu= ipo->curve.first; icu; icu= icu->next) { + for (a=0, bezt=icu->bezt; a<icu->totvert; a++, bezt++) { + /* are the times being adjusted for editing, or has editing finished */ + if (restore) { + if (only_keys == 0) { + bezt->vec[0][0]= get_action_frame(ob, bezt->vec[0][0]); + bezt->vec[2][0]= get_action_frame(ob, bezt->vec[2][0]); + } + bezt->vec[1][0]= get_action_frame(ob, bezt->vec[1][0]); + } + else { + if (only_keys == 0) { + bezt->vec[0][0]= get_action_frame_inv(ob, bezt->vec[0][0]); + bezt->vec[2][0]= get_action_frame_inv(ob, bezt->vec[2][0]); + } + bezt->vec[1][0]= get_action_frame_inv(ob, bezt->vec[1][0]); + } + } + } +} + /* *************************************************** */ diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index d4b9f9fff93..d1f41047475 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -490,12 +490,13 @@ bAnimListElem *make_new_animlistelem (void *data, short datatype, void *owner, s /* ----------------------------------------- */ -static void animdata_filter_animionchannel (ListBase *anim_data, bActionChannel *achan, int filter_mode, void *owner, short ownertype) +static int animdata_filter_actionchannel (ListBase *anim_data, bActionChannel *achan, int filter_mode, void *owner, short ownertype) { bAnimListElem *ale = NULL; bConstraintChannel *conchan; IpoCurve *icu; short owned= (owner && ownertype)? 1 : 0; + int items = 0; /* only work with this channel and its subchannels if it is visible */ if (!(filter_mode & ANIMFILTER_VISIBLE) || VISIBLE_ACHAN(achan)) { @@ -510,19 +511,20 @@ static void animdata_filter_animionchannel (ListBase *anim_data, bActionChannel if (ale) { if (owned) ale->id= owner; BLI_addtail(anim_data, ale); + items++; } } } else { /* for insert key... this check could be improved */ - return; + //return; // FIXME... } /* check if expanded - if not, continue on to next animion channel */ if (EXPANDED_ACHAN(achan) == 0 && (filter_mode & ANIMFILTER_ONLYICU)==0) { /* only exit if we don't need to include constraint channels for group-channel keyframes */ if ( !(filter_mode & ANIMFILTER_IPOKEYS) || (achan->grp == NULL) || (EXPANDED_AGRP(achan->grp)==0) ) - return; + return items; } /* ipo channels */ @@ -534,6 +536,7 @@ static void animdata_filter_animionchannel (ListBase *anim_data, bActionChannel if (ale) { if (owned) ale->id= owner; BLI_addtail(anim_data, ale); + items++; } } @@ -546,6 +549,7 @@ static void animdata_filter_animionchannel (ListBase *anim_data, bActionChannel if (ale) { if (owned) ale->id= owner; BLI_addtail(anim_data, ale); + items++; } } } @@ -562,6 +566,7 @@ static void animdata_filter_animionchannel (ListBase *anim_data, bActionChannel if (ale) { if (owned) ale->id= owner; BLI_addtail(anim_data, ale); + items++; } } @@ -574,12 +579,12 @@ static void animdata_filter_animionchannel (ListBase *anim_data, bActionChannel /* check if this conchan should only be included if it is selected */ if (!(filter_mode & ANIMFILTER_SEL) || SEL_CONCHAN(conchan)) { if (filter_mode & ANIMFILTER_IPOKEYS) { - if (ale) BLI_addtail(anim_data, ale); ale= make_new_animlistelem(conchan, ANIMTYPE_CONCHAN2, achan, ANIMTYPE_ACHAN); if (ale) { if (owned) ale->id= owner; BLI_addtail(anim_data, ale); + items++; } } else { @@ -588,6 +593,7 @@ static void animdata_filter_animionchannel (ListBase *anim_data, bActionChannel if (ale) { if (owned) ale->id= owner; BLI_addtail(anim_data, ale); + items++; } } } @@ -597,14 +603,18 @@ static void animdata_filter_animionchannel (ListBase *anim_data, bActionChannel } } } + + /* return the number of items added to the list */ + return items; } -static void animdata_filter_action (ListBase *anim_data, bAction *act, int filter_mode, void *owner, short ownertype) +static int animdata_filter_action (ListBase *anim_data, bAction *act, int filter_mode, void *owner, short ownertype) { bAnimListElem *ale=NULL; bActionGroup *agrp; bActionChannel *achan, *lastchan=NULL; short owned= (owner && ownertype) ? 1 : 0; + int items = 0; /* loop over groups */ for (agrp= act->groups.first; agrp; agrp= agrp->next) { @@ -616,6 +626,7 @@ static void animdata_filter_action (ListBase *anim_data, bAction *act, int filte if (ale) { if (owned) ale->id= owner; BLI_addtail(anim_data, ale); + items++; } } } @@ -642,7 +653,7 @@ static void animdata_filter_action (ListBase *anim_data, bAction *act, int filte { if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) { for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) { - animdata_filter_animionchannel(anim_data, achan, filter_mode, owner, ownertype); + items += animdata_filter_actionchannel(anim_data, achan, filter_mode, owner, ownertype); } /* remove group from filtered list if last element is group @@ -653,6 +664,7 @@ static void animdata_filter_action (ListBase *anim_data, bAction *act, int filte (ale->data == agrp) && (agrp->channels.first) ) { BLI_freelinkN(anim_data, ale); + items--; } } } @@ -661,19 +673,22 @@ static void animdata_filter_action (ListBase *anim_data, bAction *act, int filte /* loop over un-grouped animion channels (only if we're not only considering those channels in the animive group) */ if (!(filter_mode & ANIMFILTER_ACTGROUPED)) { - for (achan=(lastchan)?lastchan->next:act->chanbase.first; achan; achan=achan->next) { - animdata_filter_animionchannel(anim_data, achan, filter_mode, owner, ownertype); + for (achan=(lastchan)?(lastchan->next):(act->chanbase.first); achan; achan=achan->next) { + items += animdata_filter_actionchannel(anim_data, achan, filter_mode, owner, ownertype); } } + + /* return the number of items added to the list */ + return items; } -static void animdata_filter_shapekey (ListBase *anim_data, Key *key, int filter_mode, void *owner, short ownertype) +static int animdata_filter_shapekey (ListBase *anim_data, Key *key, int filter_mode, void *owner, short ownertype) { bAnimListElem *ale; KeyBlock *kb; IpoCurve *icu; short owned= (owner && ownertype)? 1 : 0; - int i; + int i, items=0; /* are we filtering for display or editing */ if (filter_mode & ANIMFILTER_FORDRAWING) { @@ -705,6 +720,7 @@ static void animdata_filter_shapekey (ListBase *anim_data, Key *key, int filter_ if (owned) ale->id= owner; BLI_addtail(anim_data, ale); + items++; } } else { @@ -715,6 +731,7 @@ static void animdata_filter_shapekey (ListBase *anim_data, Key *key, int filter_ if (ale) { if (owned) ale->id= owner; BLI_addtail(anim_data, ale); + items++; } } else { @@ -723,21 +740,26 @@ static void animdata_filter_shapekey (ListBase *anim_data, Key *key, int filter_ if (ale) { if (owned) ale->id= owner; BLI_addtail(anim_data, ale); + items++; } } } } } + + /* return the number of items added to the list */ + return items; } #if 0 // FIXME: switch this to use the bDopeSheet... -static void animdata_filter_gpencil (ListBase *anim_data, bScreen *sc, int filter_mode) +static int animdata_filter_gpencil (ListBase *anim_data, bScreen *sc, int filter_mode) { bAnimListElem *ale; ScrArea *sa, *curarea; bGPdata *gpd; bGPDlayer *gpl; + int items = 0; /* check if filtering types are appropriate */ if ( !(filter_mode & (ANIMFILTER_IPOKEYS|ANIMFILTER_ONLYICU|ANIMFILTER_ACTGROUPED)) ) @@ -762,7 +784,10 @@ static void animdata_filter_gpencil (ListBase *anim_data, bScreen *sc, int filte if ((filter_mode & ANIMFILTER_FORDRAWING) && (gpd->layers.first)) { /* add to list */ ale= make_new_animlistelem(gpd, ANIMTYPE_GPDATABLOCK, sa, ANIMTYPE_SPECIALDATA); - if (ale) BLI_addtail(anim_data, ale); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } /* only add layers if they will be visible (if drawing channels) */ @@ -775,26 +800,36 @@ static void animdata_filter_gpencil (ListBase *anim_data, bScreen *sc, int filte if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_GPL(gpl)) { /* add to list */ ale= make_new_animlistelem(gpl, ANIMTYPE_GPLAYER, gpd, ANIMTYPE_GPDATABLOCK); - if (ale) BLI_addtail(anim_data, ale); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } } } } } } + + /* return the number of items added to the list */ + return items; } #endif -static void animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) +static int animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) { bAnimListElem *ale=NULL; Object *ob= base->object; IpoCurve *icu; + int items = 0; /* include materials-expand widget? */ if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & (ANIMFILTER_IPOKEYS|ANIMFILTER_ONLYICU))) { ale= make_new_animlistelem(ob, ANIMTYPE_FILLMATD, base, ANIMTYPE_OBJECT); - if (ale) BLI_addtail(anim_data, ale); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } /* add materials? */ @@ -812,7 +847,10 @@ static void animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads // hmm... do we need to store the index of this material in the array anywhere? if (filter_mode & (ANIMFILTER_CHANNELS|ANIMFILTER_IPOKEYS)) { ale= make_new_animlistelem(ma, ANIMTYPE_DSMAT, base, ANIMTYPE_OBJECT); - if (ale) BLI_addtail(anim_data, ale); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } /* add material's ipo-curve channels? */ @@ -828,25 +866,33 @@ static void animdata_filter_dopesheet_mats (ListBase *anim_data, bDopeSheet *ads /* make owner the material not object, so that indent is not just object level */ ale->id= (ID *)ma; BLI_addtail(anim_data, ale); + items++; } } } } } } + + /* return the number of items added to the list */ + return items; } -static void animdata_filter_dopesheet_cam (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) +static int animdata_filter_dopesheet_cam (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) { bAnimListElem *ale=NULL; Object *ob= base->object; Camera *ca= (Camera *)ob->data; IpoCurve *icu; + int items = 0; /* include camera-expand widget? */ if (filter_mode & (ANIMFILTER_CHANNELS|ANIMFILTER_IPOKEYS)) { ale= make_new_animlistelem(ca, ANIMTYPE_DSCAM, base, ANIMTYPE_OBJECT); - if (ale) BLI_addtail(anim_data, ale); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } /* add camera ipo-curve channels? */ @@ -861,24 +907,32 @@ static void animdata_filter_dopesheet_cam (ListBase *anim_data, bDopeSheet *ads, if (ale) { /* make owner the material not object, so that indent is not just object level */ ale->id= (ID *)ca; - BLI_addtail(anim_data, ale); + BLI_addtail(anim_data, ale); + items++; } } } } + + /* return the number of items added to the list */ + return items; } -static void animdata_filter_dopesheet_lamp (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) +static int animdata_filter_dopesheet_lamp (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) { bAnimListElem *ale=NULL; Object *ob= base->object; Lamp *la= (Lamp *)ob->data; IpoCurve *icu; + int items = 0; /* include lamp-expand widget? */ if (filter_mode & (ANIMFILTER_CHANNELS|ANIMFILTER_IPOKEYS)) { ale= make_new_animlistelem(la, ANIMTYPE_DSLAM, base, ANIMTYPE_OBJECT); - if (ale) BLI_addtail(anim_data, ale); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } /* add lamp ipo-curve channels? */ @@ -893,24 +947,32 @@ static void animdata_filter_dopesheet_lamp (ListBase *anim_data, bDopeSheet *ads if (ale) { /* make owner the material not object, so that indent is not just object level */ ale->id= (ID *)la; - BLI_addtail(anim_data, ale); + BLI_addtail(anim_data, ale); + items++; } } } } + + /* return the number of items added to the list */ + return items; } -static void animdata_filter_dopesheet_curve (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) +static int animdata_filter_dopesheet_curve (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) { bAnimListElem *ale=NULL; Object *ob= base->object; Curve *cu= (Curve *)ob->data; IpoCurve *icu; + int items = 0; /* include curve-expand widget? */ if (filter_mode & (ANIMFILTER_CHANNELS|ANIMFILTER_IPOKEYS)) { ale= make_new_animlistelem(cu, ANIMTYPE_DSCUR, base, ANIMTYPE_OBJECT); - if (ale) BLI_addtail(anim_data, ale); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } /* add curve ipo-curve channels? */ @@ -925,40 +987,51 @@ static void animdata_filter_dopesheet_curve (ListBase *anim_data, bDopeSheet *ad if (ale) { /* make owner the material not object, so that indent is not just object level */ ale->id= (ID *)cu; - BLI_addtail(anim_data, ale); + BLI_addtail(anim_data, ale); + items++; } } } } + + /* return the number of items added to the list */ + return items; } -static void animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) +static int animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode) { bAnimListElem *ale=NULL; Scene *sce= (Scene *)ads->source; Object *ob= base->object; Key *key= ob_get_key(ob); IpoCurve *icu; + int items = 0; /* add this object as a channel first */ if (!(filter_mode & ANIMFILTER_ONLYICU) && !(filter_mode & ANIMFILTER_IPOKEYS)) { /* check if filtering by selection */ if ( !(filter_mode & ANIMFILTER_SEL) || ((base->flag & SELECT) || (base == sce->basact)) ) { ale= make_new_animlistelem(base, ANIMTYPE_OBJECT, NULL, ANIMTYPE_NONE); - if (ale) BLI_addtail(anim_data, ale); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } } /* if collapsed, don't go any further (unless adding keyframes only) */ if ( (EXPANDED_OBJC(ob) == 0) && !(filter_mode & (ANIMFILTER_IPOKEYS|ANIMFILTER_ONLYICU)) ) - return; + return items; /* IPO? */ if ((ob->ipo) && !(ads->filterflag & ADS_FILTER_NOIPOS)) { /* include ipo-expand widget? */ if (filter_mode & (ANIMFILTER_CHANNELS|ANIMFILTER_IPOKEYS)) { ale= make_new_animlistelem(ob, ANIMTYPE_FILLIPOD, base, ANIMTYPE_OBJECT); - if (ale) BLI_addtail(anim_data, ale); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } /* add ipo-curve channels? */ @@ -970,7 +1043,10 @@ static void animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, /* only if selected (if checking for selection) */ if ( !(filter_mode & ANIMFILTER_SEL) || (SEL_ICU(icu)) ) { ale= make_new_animlistelem(icu, ANIMTYPE_ICU, base, ANIMTYPE_OBJECT); - if (ale) BLI_addtail(anim_data, ale); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } } } @@ -984,13 +1060,14 @@ static void animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, if (ale) { ale->id= (ID *)ob; // err.... is this a good idea? BLI_addtail(anim_data, ale); + items++; } } /* add ipo-curve channels? */ if (EXPANDED_ACTC(ob->action) || !(filter_mode & (ANIMFILTER_CHANNELS|ANIMFILTER_FORDRAWING))) { // need to make the ownertype normal object here... (maybe type should be a separate one for clarity?) - animdata_filter_action(anim_data, ob->action, filter_mode, ob, ANIMTYPE_OBJECT); + items += animdata_filter_action(anim_data, ob->action, filter_mode, ob, ANIMTYPE_OBJECT); } } @@ -999,18 +1076,21 @@ static void animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, /* include shapekey-expand widget? */ if ((filter_mode & ANIMFILTER_CHANNELS) && !(filter_mode & (ANIMFILTER_IPOKEYS|ANIMFILTER_ONLYICU))) { ale= make_new_animlistelem(key, ANIMTYPE_DSSKEY, base, ANIMTYPE_OBJECT); - if (ale) BLI_addtail(anim_data, ale); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } /* add channels */ if (FILTER_SKE_OBJD(key) || (filter_mode & ANIMFILTER_IPOKEYS) || (filter_mode & ANIMFILTER_ONLYICU)) { - animdata_filter_shapekey (anim_data, key, filter_mode, ob, ANIMTYPE_OBJECT); + items += animdata_filter_shapekey (anim_data, key, filter_mode, ob, ANIMTYPE_OBJECT); } } /* Materials? */ if ((ob->totcol) && !(ads->filterflag & ADS_FILTER_NOMAT)) - animdata_filter_dopesheet_mats(anim_data, ads, base, filter_mode); + items += animdata_filter_dopesheet_mats(anim_data, ads, base, filter_mode); /* Object Data */ switch (ob->type) { @@ -1018,21 +1098,21 @@ static void animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, { Camera *ca= (Camera *)ob->data; if ((ca->ipo) && !(ads->filterflag & ADS_FILTER_NOCAM)) - animdata_filter_dopesheet_cam(anim_data, ads, base, filter_mode); + items += animdata_filter_dopesheet_cam(anim_data, ads, base, filter_mode); } break; case OB_LAMP: /* ---------- Lamp ----------- */ { Lamp *la= (Lamp *)ob->data; if ((la->ipo) && !(ads->filterflag & ADS_FILTER_NOLAM)) - animdata_filter_dopesheet_lamp(anim_data, ads, base, filter_mode); + items += animdata_filter_dopesheet_lamp(anim_data, ads, base, filter_mode); } break; case OB_CURVE: /* ------- Curve ---------- */ { Curve *cu= (Curve *)ob->data; if ((cu->ipo) && !(ads->filterflag & ADS_FILTER_NOCUR)) - animdata_filter_dopesheet_curve(anim_data, ads, base, filter_mode); + items += animdata_filter_dopesheet_curve(anim_data, ads, base, filter_mode); } break; } @@ -1046,7 +1126,10 @@ static void animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, && !(filter_mode & ANIMFILTER_IPOKEYS) ) { ale= make_new_animlistelem(ob, ANIMTYPE_FILLCOND, base, ANIMTYPE_OBJECT); - if (ale) BLI_addtail(anim_data, ale); + if (ale) { + BLI_addtail(anim_data, ale); + items++; + } } /* add constraint channels? */ @@ -1062,6 +1145,7 @@ static void animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, if (ale) { ale->id= (ID *)ob; BLI_addtail(anim_data, ale); + items++; } } else { @@ -1069,6 +1153,7 @@ static void animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, if (ale) { ale->id= (ID *)ob; BLI_addtail(anim_data, ale); + items++; } } } @@ -1076,18 +1161,22 @@ static void animdata_filter_dopesheet_ob (ListBase *anim_data, bDopeSheet *ads, } } } + + /* return the number of items added to the list */ + return items; } // TODO: implement pinning... (if and when pinning is done, what we need to do is to provide freeing mechanisms - to protect against data that was deleted) -static void animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int filter_mode) +static int animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int filter_mode) { Scene *sce= (Scene *)ads->source; Base *base; + int items = 0; /* check that we do indeed have a scene */ if ((ads->source == NULL) || (GS(ads->source->name)!=ID_SCE)) { printf("DopeSheet Error: Not scene! \n"); - return; + return 0; } /* loop over all bases in the scene */ @@ -1199,21 +1288,27 @@ static void animdata_filter_dopesheet (ListBase *anim_data, bDopeSheet *ads, int } /* since we're still here, this object should be usable */ - animdata_filter_dopesheet_ob(anim_data, ads, base, filter_mode); + items += animdata_filter_dopesheet_ob(anim_data, ads, base, filter_mode); } } + + /* return the number of items in the list */ + return items; } /* ----------- Public API --------------- */ -/* This function filters the active data source to leave only the desired - * data types. 'Public' api call. +/* This function filters the active data source to leave only animation channels suitable for + * usage by the caller. It will return the length of the list + * * *act_data: is a pointer to a ListBase, to which the filtered animation channels * will be placed for use. * filter_mode: how should the data be filtered - bitmapping accessed flags */ -void ANIM_animdata_filter (ListBase *anim_data, int filter_mode, void *data, short datatype) +int ANIM_animdata_filter (ListBase *anim_data, int filter_mode, void *data, short datatype) { + int items = 0; + /* only filter data if there's somewhere to put it */ if (data && anim_data) { bAnimListElem *ale, *next; @@ -1221,20 +1316,21 @@ void ANIM_animdata_filter (ListBase *anim_data, int filter_mode, void *data, sho /* firstly filter the data */ switch (datatype) { case ANIMCONT_ACTION: - animdata_filter_action(anim_data, data, filter_mode, NULL, ANIMTYPE_NONE); + items= animdata_filter_action(anim_data, data, filter_mode, NULL, ANIMTYPE_NONE); break; case ANIMCONT_SHAPEKEY: - animdata_filter_shapekey(anim_data, data, filter_mode, NULL, ANIMTYPE_NONE); + items= animdata_filter_shapekey(anim_data, data, filter_mode, NULL, ANIMTYPE_NONE); break; case ANIMCONT_GPENCIL: - //animdata_filter_gpencil(anim_data, data, filter_mode); + //items= animdata_filter_gpencil(anim_data, data, filter_mode); break; case ANIMCONT_DOPESHEET: - animdata_filter_dopesheet(anim_data, data, filter_mode); + items= animdata_filter_dopesheet(anim_data, data, filter_mode); break; case ANIMCONT_IPO: // FIXME: this will be used for showing a single IPO-block (not too useful from animator perspective though!) + //items= 0; break; } @@ -1243,17 +1339,26 @@ void ANIM_animdata_filter (ListBase *anim_data, int filter_mode, void *data, sho for (ale= anim_data->first; ale; ale= next) { next= ale->next; - if (ale->type == ANIMTYPE_NONE) + if (ale->type == ANIMTYPE_NONE) { + items--; BLI_freelinkN(anim_data, ale); + } if (filter_mode & ANIMFILTER_IPOKEYS) { - if (ale->datatype != ALE_IPO) + if (ale->datatype != ALE_IPO) { + items--; BLI_freelinkN(anim_data, ale); - else if (ale->key_data == NULL) + } + else if (ale->key_data == NULL) { + items--; BLI_freelinkN(anim_data, ale); + } } } } + + /* return the number of items in the list */ + return items; } /* ************************************************************ */ diff --git a/source/blender/editors/animation/anim_keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index b72b2bd27fa..b72b2bd27fa 100644 --- a/source/blender/editors/animation/anim_keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c new file mode 100644 index 00000000000..152d07b83f6 --- /dev/null +++ b/source/blender/editors/animation/keyframes_edit.c @@ -0,0 +1,785 @@ +/** + * $Id: + * + * ***** BEGIN GPL 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. + * + * 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. + * + * Contributor(s): Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "DNA_curve_types.h" +#include "DNA_ipo_types.h" +#include "DNA_key_types.h" +#include "DNA_object_types.h" +#include "DNA_space_types.h" +#include "DNA_scene_types.h" + +#include "BKE_action.h" +#include "BKE_ipo.h" +#include "BKE_key.h" +#include "BKE_utildefines.h" + +#include "ED_keyframes_edit.h" +#include "ED_markers.h" + +/* This file defines an API and set of callback-operators for editing keyframe data. + * + * Two API functions are defined for actually performing the operations on the data: + * ipo_keys_bezier_loop() and icu_keys_bezier_loop() + * which take the data they operate on, a few callbacks defining what operations to perform. + * + * As operators which work on keyframes usually apply the same operation on all BezTriples in + * every channel, the code has been optimised providing a set of functions which will get the + * appropriate bezier-modify function to set. These functions (ANIM_editkeyframes_*) will need + * to be called before getting any channels. + * + * - Joshua Leung, Dec 2008 + */ + +/* ************************************************************************** */ +/* IPO Editing Loops - Exposed API */ + +// FIXME: it would be useful to be able to supply custom properties to the bezt function... +// workaround for those callbacks that need this now, is to set globals... + +/* This function is used to loop over BezTriples in the given IpoCurve, applying a given + * operation on them, and optionally applies an IPO-curve validate function afterwards. + */ +short icu_keys_bezier_loop(Scene *scene, IpoCurve *icu, BeztEditFunc bezt_cb, IcuEditFunc icu_cb) +{ + BezTriple *bezt; + int b; + + /* if function to apply to bezier curves is set, then loop through executing it on beztriples */ + if (bezt_cb) { + for (b=0, bezt=icu->bezt; b < icu->totvert; b++, bezt++) { + /* Exit with return-code '1' if function returns positive + * This is useful if finding if some BezTriple satisfies a condition. + */ + if (bezt_cb(scene, bezt)) return 1; + } + } + + /* if ipocurve_function has been specified then execute it */ + if (icu_cb) + icu_cb(icu); + + /* done */ + return 0; +} + +/* This function is used to loop over the IPO curves (and subsequently the keyframes in them) */ +short ipo_keys_bezier_loop(Scene *scene, Ipo *ipo, BeztEditFunc bezt_cb, IcuEditFunc icu_cb) +{ + IpoCurve *icu; + + /* Sanity check */ + if (ipo == NULL) + return 0; + + /* Loop through each curve in the Ipo */ + for (icu= ipo->curve.first; icu; icu=icu->next) { + if (icu_keys_bezier_loop(scene, icu, bezt_cb, icu_cb)) + return 1; + } + + return 0; +} + +/* ******************************************* */ +/* Transform */ + +static short snap_bezier_nearest(Scene *scene, BezTriple *bezt) +{ + if (bezt->f2 & SELECT) + bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]+0.5)); + return 0; +} + +static short snap_bezier_nearestsec(Scene *scene, BezTriple *bezt) +{ + float secf = FPS; + if (bezt->f2 & SELECT) + bezt->vec[1][0]= (float)(floor(bezt->vec[1][0]/secf + 0.5f) * secf); + return 0; +} + +static short snap_bezier_cframe(Scene *scene, BezTriple *bezt) +{ + if (bezt->f2 & SELECT) + bezt->vec[1][0]= (float)CFRA; + return 0; +} + +static short snap_bezier_nearmarker(Scene *scene, BezTriple *bezt) +{ + //if (bezt->f2 & SELECT) + // bezt->vec[1][0]= (float)find_nearest_marker_time(bezt->vec[1][0]); // XXX missing function! + return 0; +} + +// calchandles_ipocurve +BeztEditFunc ANIM_editkeys_snap(short type) +{ + switch (type) { + case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */ + return snap_bezier_nearest; + case SNAP_KEYS_CURFRAME: /* snap to current frame */ + return snap_bezier_cframe; + case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */ + return snap_bezier_nearmarker; + case SNAP_KEYS_NEARSEC: /* snap to nearest second */ + return snap_bezier_nearestsec; + default: /* just in case */ + return snap_bezier_nearest; + } +} + +/* --------- */ + +static short mirror_bezier_cframe(Scene *scene, BezTriple *bezt) +{ + float diff; + + if (bezt->f2 & SELECT) { + diff= ((float)CFRA - bezt->vec[1][0]); + bezt->vec[1][0]= ((float)CFRA + diff); + } + + return 0; +} + +static short mirror_bezier_yaxis(Scene *scene, BezTriple *bezt) +{ + float diff; + + if (bezt->f2 & SELECT) { + diff= (0.0f - bezt->vec[1][0]); + bezt->vec[1][0]= (0.0f + diff); + } + + return 0; +} + +static short mirror_bezier_xaxis(Scene *scene, BezTriple *bezt) +{ + float diff; + + if (bezt->f2 & SELECT) { + diff= (0.0f - bezt->vec[1][1]); + bezt->vec[1][1]= (0.0f + diff); + } + + return 0; +} + +static short mirror_bezier_marker(Scene *scene, BezTriple *bezt) +{ + static TimeMarker *marker; + static short initialised = 0; + + /* In order for this mirror function to work without + * any extra arguments being added, we use the case + * of bezt==NULL to denote that we should find the + * marker to mirror over. The static pointer is safe + * to use this way, as it will be set to null after + * each cycle in which this is called. + */ + + if (bezt) { + /* mirroring time */ + if ((bezt->f2 & SELECT) && (marker)) { + const float diff= (marker->frame - bezt->vec[1][0]); + bezt->vec[1][0]= (marker->frame + diff); + } + } + else { + /* initialisation time */ + if (initialised) { + /* reset everything for safety */ + marker = NULL; + initialised = 0; + } + else { + /* try to find a marker */ + for (marker= scene->markers.first; marker; marker=marker->next) { + if (marker->flag & SELECT) { + initialised = 1; + break; + } + } + + if (initialised == 0) + marker = NULL; + } + } + + return 0; +} + +/* Note: for markers case, need to set global vars (eww...) */ +// calchandles_ipocurve +BeztEditFunc ANIM_editkeyframes_mirror(short type) +{ + switch (type) { + case 1: /* mirror over current frame */ + return mirror_bezier_cframe; + case 2: /* mirror over frame 0 */ + return mirror_bezier_yaxis; + case 3: /* mirror over value 0 */ + return mirror_bezier_xaxis; + case 4: /* mirror over marker */ + return mirror_bezier_marker; // XXX in past, this func was called before/after with NULL, probably will need globals instead + default: /* just in case */ + return mirror_bezier_yaxis; + break; + } +} + +/* This function is called to calculate the average location of the + * selected keyframes, and place the current frame at that location. + * + * It must be called like so: + * snap_cfra_ipo_keys(scene, NULL, -1); // initialise the static vars first + * for (ipo...) snap_cfra_ipo_keys(scene, ipo, 0); // sum up keyframe times + * snap_cfra_ipo_keys(scene, NULL, 1); // set current frame after taking average + */ +void snap_cfra_ipo_keys(Scene *scene, Ipo *ipo, short mode) +{ + static int cfra; + static int tot; + + IpoCurve *icu; + BezTriple *bezt; + int a; + + + if (mode == -1) { + /* initialise a new snap-operation */ + cfra= 0; + tot= 0; + } + else if (mode == 1) { + /* set current frame - using average frame */ + if (tot != 0) + CFRA = cfra / tot; + } + else { + /* loop through keys in ipo, summing the frame + * numbers of those that are selected + */ + if (ipo == NULL) + return; + + for (icu= ipo->curve.first; icu; icu= icu->next) { + for (a=0, bezt=icu->bezt; a < icu->totvert; a++, bezt++) { + if (BEZSELECTED(bezt)) { + cfra += bezt->vec[1][0]; + tot++; + } + } + } + } +} + +/* ******************************************* */ +/* Settings */ + +/* Sets the selected bezier handles to type 'auto' */ +static short set_bezier_auto(Scene *scene, BezTriple *bezt) +{ + /* is a handle selected? If so set it to type auto */ + if((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) { + if (bezt->f1 & SELECT) bezt->h1= 1; /* the secret code for auto */ + if (bezt->f3 & SELECT) bezt->h2= 1; + + /* if the handles are not of the same type, set them + * to type free + */ + if (bezt->h1 != bezt->h2) { + if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE; + if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE; + } + } + return 0; +} + +/* Sets the selected bezier handles to type 'vector' */ +static short set_bezier_vector(Scene *scene, BezTriple *bezt) +{ + /* is a handle selected? If so set it to type vector */ + if ((bezt->f1 & SELECT) || (bezt->f3 & SELECT)) { + if (bezt->f1 & SELECT) bezt->h1= HD_VECT; + if (bezt->f3 & SELECT) bezt->h2= HD_VECT; + + /* if the handles are not of the same type, set them + * to type free + */ + if (bezt->h1 != bezt->h2) { + if ELEM(bezt->h1, HD_ALIGN, HD_AUTO) bezt->h1= HD_FREE; + if ELEM(bezt->h2, HD_ALIGN, HD_AUTO) bezt->h2= HD_FREE; + } + } + return 0; +} + +#if 0 // xxx currently not used (only used by old code as a check) +static short bezier_isfree(Scene *scene, BezTriple *bezt) +{ + /* queries whether the handle should be set + * to type 'free' or 'align' + */ + if ((bezt->f1 & SELECT) && (bezt->h1)) return 1; + if ((bezt->f3 & SELECT) && (bezt->h2)) return 1; + return 0; +} + +static short set_bezier_align(Scene *scene, BezTriple *bezt) +{ + /* Sets selected bezier handles to type 'align' */ + if (bezt->f1 & SELECT) bezt->h1= HD_ALIGN; + if (bezt->f3 & SELECT) bezt->h2= HD_ALIGN; + return 0; +} +#endif // xxx currently not used (only used by old code as a check, but can't replicate that now) + +static short set_bezier_free(Scene *scene, BezTriple *bezt) +{ + /* Sets selected bezier handles to type 'free' */ + if (bezt->f1 & SELECT) bezt->h1= HD_FREE; + if (bezt->f3 & SELECT) bezt->h2= HD_FREE; + return 0; +} + +/* Set all Bezier Handles to a single type */ +// calchandles_ipocurve +BeztEditFunc ANIM_editkeyframes_sethandles(short code) +{ + switch (code) { + case 1: /* auto */ + return set_bezier_auto; + case 2: /* vector */ + return set_bezier_vector; + + default: /* free or align? */ + return set_bezier_free; // err.. to set align, we need 'align' to be set + } +} + +#if 0 +void sethandles_ipo_keys(Ipo *ipo, int code) +{ + /* this function lets you set bezier handles all to + * one type for some Ipo's (e.g. with hotkeys through + * the action window). + */ + + /* code==1: set autohandle */ + /* code==2: set vectorhandle */ + /* als code==3 (HD_ALIGN) toggelt het, vectorhandles worden HD_FREE */ + + switch (code) { + case 1: /* auto */ + ipo_keys_bezier_loop(ipo, set_bezier_auto, calchandles_ipocurve); + break; + case 2: /* vector */ + ipo_keys_bezier_loop(ipo, set_bezier_vector, calchandles_ipocurve); + break; + default: /* free or align? */ + if (ipo_keys_bezier_loop(ipo, bezier_isfree, NULL)) /* free */ + ipo_keys_bezier_loop(ipo, set_bezier_free, calchandles_ipocurve); + else /* align */ + ipo_keys_bezier_loop(ipo, set_bezier_align, calchandles_ipocurve); + break; + } +} +#endif + +/* ------- */ + +void set_ipocurve_mixed(IpoCurve *icu) +{ + /* Sets the type of the IPO curve to mixed, as some (selected) + * keyframes were set to other interpolation modes + */ + icu->ipo= IPO_MIXED; + + /* recalculate handles, as some changes may have occurred */ + calchandles_ipocurve(icu); +} + +static short set_bezt_constant(Scene *scene, BezTriple *bezt) +{ + if (bezt->f2 & SELECT) + bezt->ipo= IPO_CONST; + return 0; +} + +static short set_bezt_linear(Scene *scene, BezTriple *bezt) +{ + if (bezt->f2 & SELECT) + bezt->ipo= IPO_LIN; + return 0; +} + +static short set_bezt_bezier(Scene *scene, BezTriple *bezt) +{ + if (bezt->f2 & SELECT) + bezt->ipo= IPO_BEZ; + return 0; +} + +/* Set the interpolation type of the selected BezTriples in each IPO curve to the specified one */ +// set_ipocurve_mixed() ! +BeztEditFunc ANIM_editkeyframes_ipo(short code) +{ + switch (code) { + case 1: /* constant */ + return set_bezt_constant; + case 2: /* linear */ + return set_bezt_linear; + default: /* bezier */ + return set_bezt_bezier; + } +} + +#if 0 +void setipotype_ipo(Ipo *ipo, int code) +{ + /* Sets the type of the selected bezts in each ipo curve in the + * Ipo to a value based on the code + */ + switch (code) { + case 1: + ipo_keys_bezier_loop(ipo, set_bezt_constant, set_ipocurve_mixed); + break; + case 2: + ipo_keys_bezier_loop(ipo, set_bezt_linear, set_ipocurve_mixed); + break; + case 3: + ipo_keys_bezier_loop(ipo, set_bezt_bezier, set_ipocurve_mixed); + break; + } +} +#endif + +// XXX will we keep this? +void setexprap_ipoloop(Ipo *ipo, int code) +{ + IpoCurve *icu; + + /* Loop through each curve in the Ipo */ + for (icu=ipo->curve.first; icu; icu=icu->next) + icu->extrap= code; +} + +/* ******************************************* */ +/* Selection */ + +static short select_bezier_add(Scene *scene, BezTriple *bezt) +{ + /* Select the bezier triple */ + BEZ_SEL(bezt); + return 0; +} + +static short select_bezier_subtract(Scene *scene, BezTriple *bezt) +{ + /* Deselect the bezier triple */ + BEZ_DESEL(bezt); + return 0; +} + +static short select_bezier_invert(Scene *scene, BezTriple *bezt) +{ + /* Invert the selection for the bezier triple */ + bezt->f2 ^= SELECT; + if (bezt->f2 & SELECT) { + bezt->f1 |= SELECT; + bezt->f3 |= SELECT; + } + else { + bezt->f1 &= ~SELECT; + bezt->f3 &= ~SELECT; + } + return 0; +} + +// NULL +BeztEditFunc ANIM_editkeyframes_select(short selectmode) +{ + switch (selectmode) { + case SELECT_ADD: /* add */ + return select_bezier_add; + case SELECT_SUBTRACT: /* subtract */ + return select_bezier_subtract; + case SELECT_INVERT: /* invert */ + return select_bezier_invert; + default: /* replace (need to clear all, then add) */ + return select_bezier_add; + } +} + + +short is_ipo_key_selected(Ipo *ipo) +{ + IpoCurve *icu; + BezTriple *bezt; + int i; + + if (ipo == NULL) + return 0; + + for (icu=ipo->curve.first; icu; icu=icu->next) { + for (i=0, bezt=icu->bezt; i<icu->totvert; i++, bezt++) { + if (BEZSELECTED(bezt)) + return 1; + } + } + + return 0; +} + +void set_ipo_key_selection(Ipo *ipo, short sel) +{ + IpoCurve *icu; + BezTriple *bezt; + int i; + + if (ipo == NULL) + return; + + for (icu=ipo->curve.first; icu; icu=icu->next) { + for (i=0, bezt=icu->bezt; i<icu->totvert; i++, bezt++) { + if (sel == 2) { + BEZ_INVSEL(bezt); + } + else if (sel == 1) { + BEZ_SEL(bezt); + } + else { + BEZ_DESEL(bezt); + } + } + } +} + +// err... this is this still used? +int fullselect_ipo_keys(Ipo *ipo) +{ + IpoCurve *icu; + int tvtot = 0; + int i; + + if (!ipo) + return tvtot; + + for (icu=ipo->curve.first; icu; icu=icu->next) { + for (i=0; i<icu->totvert; i++) { + if (icu->bezt[i].f2 & SELECT) { + tvtot+=3; + icu->bezt[i].f1 |= SELECT; + icu->bezt[i].f3 |= SELECT; + } + } + } + + return tvtot; +} + + +void borderselect_icu_key(Scene *scene, IpoCurve *icu, float xmin, float xmax, BeztEditFunc select_cb) +{ + /* Selects all bezier triples in the Ipocurve + * between times xmin and xmax, using the selection + * function. + */ + BezTriple *bezt; + int i; + + /* loop through all of the bezier triples in + * the Ipocurve -- if the triple occurs between + * times xmin and xmax then select it using the selection + * function + */ + for (i=0, bezt=icu->bezt; i<icu->totvert; i++, bezt++) { + if ((bezt->vec[1][0] > xmin) && (bezt->vec[1][0] < xmax)) { + select_cb(scene, bezt); + } + } +} + +void borderselect_ipo_key(Scene *scene, Ipo *ipo, float xmin, float xmax, short selectmode) +{ + /* Selects all bezier triples in each Ipocurve of the + * Ipo between times xmin and xmax, using the selection mode. + */ + + IpoCurve *icu; + BeztEditFunc select_cb; + + /* If the ipo is no good then return */ + if (ipo == NULL) + return; + + /* Set the selection function based on the + * selection mode. + */ + select_cb= ANIM_editkeyframes_select(selectmode); + if (select_cb == NULL) + return; + + /* loop through all of the bezier triples in all + * of the Ipocurves -- if the triple occurs between + * times xmin and xmax then select it using the selection + * function + */ + for (icu=ipo->curve.first; icu; icu=icu->next) { + borderselect_icu_key(scene, icu, xmin, xmax, select_cb); + } +} + + +#if 0 +void select_ipo_bezier_keys(Ipo *ipo, int selectmode) +{ + /* Select all of the beziers in all + * of the Ipo curves belonging to the + * Ipo, using the selection mode. + */ + switch (selectmode) { + case SELECT_ADD: + ipo_keys_bezier_loop(ipo, select_bezier_add, NULL); + break; + case SELECT_SUBTRACT: + ipo_keys_bezier_loop(ipo, select_bezier_subtract, NULL); + break; + case SELECT_INVERT: + ipo_keys_bezier_loop(ipo, select_bezier_invert, NULL); + break; + } +} + +void select_icu_bezier_keys(IpoCurve *icu, int selectmode) +{ + /* Select all of the beziers in all + * of the Ipo curves belonging to the + * Ipo, using the selection mode. + */ + switch (selectmode) { + case SELECT_ADD: + icu_keys_bezier_loop(icu, select_bezier_add, NULL); + break; + case SELECT_SUBTRACT: + icu_keys_bezier_loop(icu, select_bezier_subtract, NULL); + break; + case SELECT_INVERT: + icu_keys_bezier_loop(icu, select_bezier_invert, NULL); + break; + } +} +#endif + +void select_icu_key(Scene *scene, IpoCurve *icu, float selx, short selectmode) +{ + /* Selects all bezier triples in the Ipocurve + * at time selx, using the selection mode. + * This is kind of sloppy the obvious similarities + * with the above function, forgive me ... + */ + BeztEditFunc select_cb; + BezTriple *bezt; + int i; + + /* If the icu is no good then return */ + if (icu == NULL) + return; + + /* Set the selection function based on the selection mode. */ + switch (selectmode) { + case SELECT_ADD: + select_cb = select_bezier_add; + break; + case SELECT_SUBTRACT: + select_cb = select_bezier_subtract; + break; + case SELECT_INVERT: + select_cb = select_bezier_invert; + break; + default: + return; + } + + /* loop through all of the bezier triples in + * the Ipocurve -- if the triple occurs at + * time selx then select it using the selection + * function + */ + for (i=0, bezt=icu->bezt; i<icu->totvert; i++, bezt++) { + if (bezt->vec[1][0] == selx) { + select_cb(scene, bezt); + } + } +} + +void select_ipo_key(Scene *scene, Ipo *ipo, float selx, short selectmode) +{ + /* Selects all bezier triples in each Ipocurve of the + * Ipo at time selx, using the selection mode. + */ + IpoCurve *icu; + BezTriple *bezt; + BeztEditFunc select_cb; + int i; + + /* If the ipo is no good then return */ + if (ipo == NULL) + return; + + /* Set the selection function based on the + * selection mode. + */ + select_cb= ANIM_editkeyframes_select(selectmode); + if (select_cb == NULL) + return; + + /* loop through all of the bezier triples in all + * of the Ipocurves -- if the triple occurs at + * time selx then select it using the selection + * function + */ + for (icu=ipo->curve.first; icu; icu=icu->next) { + for (i=0, bezt=icu->bezt; i<icu->totvert; i++, bezt++) { + if (bezt->vec[1][0] == selx) { + select_cb(scene, bezt); + } + } + } +} + + diff --git a/source/blender/editors/animation/anim_keyframing.c b/source/blender/editors/animation/keyframing.c index a86cf3719d3..a86cf3719d3 100644 --- a/source/blender/editors/animation/anim_keyframing.c +++ b/source/blender/editors/animation/keyframing.c diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index aa1333f3ce7..efd104081c1 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -32,6 +32,9 @@ struct ID; struct ListBase; struct bContext; +struct wmWindowManager; +struct ScrArea; +struct ARegion; struct View2D; struct gla2DDrawInfo; struct Object; @@ -54,6 +57,7 @@ typedef struct bAnimContext { short spacetype; /* sa->spacetype */ short regiontype; /* active region -> type (channels or main) */ struct ScrArea *sa; /* editor */ + struct ARegion *ar; /* region within editor */ struct Scene *scene; /* active scene */ struct Object *obact; /* active object */ @@ -215,7 +219,7 @@ typedef enum eAnimFilter_Flags { /* ---------------- API -------------------- */ /* Obtain list of filtered Animation channels to operate on */ -void ANIM_animdata_filter(struct ListBase *anim_data, int filter_mode, void *data, short datatype); +int ANIM_animdata_filter(struct ListBase *anim_data, int filter_mode, void *data, short datatype); /* Obtain current anim-data context from Blender Context info */ /** Example usage (example to be removed...): @@ -268,9 +272,12 @@ unsigned int ipo_rainbow(int cur, int tot); /* Obtain the Object providing NLA-scaling for the given channel if applicable */ struct Object *ANIM_nla_mapping_get(bAnimContext *ac, bAnimListElem *ale); -/* set/clear temporary mapping of coordinates from 'local-action' time to 'global-nla-scaled' time */ +/* Set/clear temporary mapping of coordinates from 'local-action' time to 'global-nla-scaled' time */ void ANIM_nla_mapping_draw(struct gla2DDrawInfo *di, struct Object *ob, short restore); +/* Apply/Unapply NLA mapping to all keyframes in the nominated IPO block */ +void ANIM_nla_mapping_apply(struct Object *ob, struct Ipo *ipo, short restore, short only_keys); + /* ------------- xxx macros ----------------------- */ #define BEZSELECTED(bezt) ((bezt->f2 & SELECT) || (bezt->f1 & SELECT) || (bezt->f3 & SELECT)) diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h new file mode 100644 index 00000000000..ed3c09c8a98 --- /dev/null +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -0,0 +1,104 @@ +/** + * $Id: + * + * ***** BEGIN GPL 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. + * + * 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) 2008 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef ED_KEYFRAMES_EDIT_H +#define ED_KEYFRAMES_EDIT_H + +struct Ipo; +struct IpoCurve; +struct BezTriple; +struct Scene; + +/* ************************************************ */ +/* Common Macros and Defines */ + +/* --------- BezTriple Selection ------------- */ + +#define BEZSELECTED(bezt) ((bezt->f2 & SELECT) || (bezt->f1 & SELECT) || (bezt->f3 & SELECT)) + +#define BEZ_SEL(bezt) { (bezt)->f1 |= SELECT; (bezt)->f2 |= SELECT; (bezt)->f3 |= SELECT; } +#define BEZ_DESEL(bezt) { (bezt)->f1 &= ~SELECT; (bezt)->f2 &= ~SELECT; (bezt)->f3 &= ~SELECT; } +#define BEZ_INVSEL(bezt) { (bezt)->f1 ^= SELECT; (bezt)->f2 ^= SELECT; (bezt)->f3 ^= SELECT; } + +/* --------- Tool Flags ------------ */ + +/* select tools */ +typedef enum eEditKeyframes_Select { + SELECT_REPLACE = (1<<0), + SELECT_ADD = (1<<1), + SELECT_SUBTRACT = (1<<2), + SELECT_INVERT = (1<<4), +} eEditKeyframes_Select; + +/* snapping tools */ +typedef enum eEditKeyframes_Snap { + SNAP_KEYS_NEARFRAME = 1, + SNAP_KEYS_CURFRAME, + SNAP_KEYS_NEARMARKER, + SNAP_KEYS_NEARSEC, +} eEditKeyframes_Snap; + +/* mirroring tools */ +//typedef enum eEditKeyframes_Mirror { + +//} eEditKeyframes_Mirror; + +/* ************************************************ */ +/* Editing API */ + +/* ------- Function Pointer Typedefs --------------- */ + + /* callback function that refreshes the IPO curve after use */ +typedef void (*IcuEditFunc)(struct IpoCurve *icu); +typedef short (*BeztEditFunc)(struct Scene *scene, struct BezTriple *bezt); + +/* ------------- Looping API ------------------- */ + +short icu_keys_bezier_loop(struct Scene *scene, struct IpoCurve *icu, BeztEditFunc bezt_cb, IcuEditFunc icu_cb); +short ipo_keys_bezier_loop(struct Scene *scene, struct Ipo *ipo, BeztEditFunc bezt_cb, IcuEditFunc icu_cb); + +/* ------------ BezTriple Callback Getters --------------- */ + +BeztEditFunc ANIM_editkeyframes_snap(short mode); +BeztEditFunc ANIM_editkeyframes_mirror(short mode); +BeztEditFunc ANIM_editkeyframes_select(short mode); +BeztEditFunc ANIM_editkeyframes_handles(short mode); +BeztEditFunc ANIM_editkeyframes_ipo(short mode); + +/* ------------ Helper Funcs -------------- */ +// XXX will these be needed to set globals for some funcs? + +/* ************************************************ */ + +void select_ipo_key(struct Scene *scene, struct Ipo *ipo, float selx, short selectmode); +void select_icu_key(struct Scene *scene, struct IpoCurve *icu, float selx, short selectmode); + + +/* ************************************************ */ + +#endif /* ED_KEYFRAMES_EDIT_H */ diff --git a/source/blender/editors/include/ED_markers.h b/source/blender/editors/include/ED_markers.h index 49f805e4ddb..001c61c1589 100644 --- a/source/blender/editors/include/ED_markers.h +++ b/source/blender/editors/include/ED_markers.h @@ -28,6 +28,7 @@ #ifndef ED_MARKERS_H #define ED_MARKERS_H + /* flags for drawing markers */ enum { DRAW_MARKERS_LINES = (1<<0), @@ -35,8 +36,9 @@ enum { }; struct wmWindowManager; +struct bContext; -void draw_markers_time(const bContext *C, int flag); +void draw_markers_time(const struct bContext *C, int flag); /* called in screen_ops.c:ED_operatortypes_screen() */ void ED_marker_operatortypes(void); diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 19054f48dba..8992e71759c 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -167,8 +167,12 @@ void UI_view2d_to_region_no_clip(struct View2D *v2d, float x, float y, short *re /* utilities */ struct View2D *UI_view2d_fromcontext(const struct bContext *C); struct View2D *UI_view2d_fromcontext_rwin(const struct bContext *C); + void UI_view2d_getscale(struct View2D *v2d, float *x, float *y); +short UI_view2d_mouse_in_scrollers(const struct bContext *C, struct View2D *v2d, int x, int y); + + /* operators */ void ui_view2d_operatortypes(void); void UI_view2d_keymap(struct wmWindowManager *wm); diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index f827d68f697..2398f8e2e35 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -1689,3 +1689,32 @@ void UI_view2d_getscale(View2D *v2d, float *x, float *y) if (y) *y = (v2d->mask.ymax - v2d->mask.ymin) / (v2d->cur.ymax - v2d->cur.ymin); } +/* Check if mouse is within scrollers + * - Returns appropriate code for match + * 'h' = in horizontal scroller + * 'v' = in vertical scroller + * 0 = not in scroller + * + * - x,y = mouse coordinates in screen (not region) space + */ +short UI_view2d_mouse_in_scrollers (const bContext *C, View2D *v2d, int x, int y) +{ + ARegion *ar= CTX_wm_region(C); + int co[2]; + + /* clamp x,y to region-coordinates first */ + co[0]= x - ar->winrct.xmin; + co[1]= y - ar->winrct.ymin; + + /* check if within scrollbars */ + if (v2d->scroll & V2D_SCROLL_HORIZONTAL) { + if (IN_2D_HORIZ_SCROLL(v2d, co)) return 'h'; + } + if (v2d->scroll & V2D_SCROLL_VERTICAL) { + if (IN_2D_VERT_SCROLL(v2d, co)) return 'v'; + } + + /* not found */ + return 0; +} + diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c index 132413477f1..40017669345 100644 --- a/source/blender/editors/interface/view2d_ops.c +++ b/source/blender/editors/interface/view2d_ops.c @@ -53,38 +53,6 @@ #include "UI_resources.h" #include "UI_view2d.h" -/* ********************************************************* */ -/* General Polling Funcs */ - -/* Check if mouse is within scrollbars - * - Returns appropriate code for match - * 'h' = in horizontal scrollbar - * 'v' = in vertical scrollbar - * 0 = not in scrollbar - * - * - x,y = mouse coordinates in screen (not region) space - */ -static short mouse_in_v2d_scrollers (const bContext *C, View2D *v2d, int x, int y) -{ - ARegion *ar= CTX_wm_region(C); - int co[2]; - - /* clamp x,y to region-coordinates first */ - co[0]= x - ar->winrct.xmin; - co[1]= y - ar->winrct.ymin; - - /* check if within scrollbars */ - if (v2d->scroll & V2D_SCROLL_HORIZONTAL) { - if (IN_2D_HORIZ_SCROLL(v2d, co)) return 'h'; - } - if (v2d->scroll & V2D_SCROLL_VERTICAL) { - if (IN_2D_VERT_SCROLL(v2d, co)) return 'v'; - } - - /* not found */ - return 0; -} - /* ********************************************************* */ /* VIEW PANNING OPERATOR */ @@ -1106,7 +1074,7 @@ static int scroller_activate_invoke(bContext *C, wmOperator *op, wmEvent *event) v2d= &ar->v2d; /* check if mouse in scrollbars, if they're enabled */ - in_scroller= mouse_in_v2d_scrollers(C, v2d, event->x, event->y); + in_scroller= UI_view2d_mouse_in_scrollers(C, v2d, event->x, event->y); /* if in a scroller, init customdata then set modal handler which will catch mousedown to start doing useful stuff */ if (in_scroller) { diff --git a/source/blender/editors/space_action/SConscript b/source/blender/editors/space_action/SConscript index 3d22e8ed5ab..01684e1c2ee 100644 --- a/source/blender/editors/space_action/SConscript +++ b/source/blender/editors/space_action/SConscript @@ -3,7 +3,7 @@ Import ('env') sources = env.Glob('*.c') -incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf' +incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../makesrna ../../imbuf' incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include' env.BlenderLib ( 'bf_editors_space_action', sources, Split(incs), [], libtype=['core','intern'], priority=[33, 37] ) diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h index 67fdff6190e..ef9ab5a9d66 100644 --- a/source/blender/editors/space_action/action_intern.h +++ b/source/blender/editors/space_action/action_intern.h @@ -32,6 +32,8 @@ struct bContext; struct bAnimContext; struct SpaceAction; struct ARegion; +struct wmWindowManager; +struct wmOperatorType; /* internal exports only */ @@ -42,6 +44,12 @@ void draw_channel_strips(struct bAnimContext *ac, struct SpaceAction *saction, s /* action_header.c */ void action_header_buttons(const struct bContext *C, struct ARegion *ar); +/* action_select.c */ +void ED_ACT_OT_keyframes_clickselect(struct wmOperatorType *ot); + +/* action_ops.c */ +void action_operatortypes(void); +void action_keymap(struct wmWindowManager *wm); #endif /* ED_ACTION_INTERN_H */ diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c new file mode 100644 index 00000000000..9a64a026f81 --- /dev/null +++ b/source/blender/editors/space_action/action_ops.c @@ -0,0 +1,91 @@ +/** + * $Id: + * + * ***** BEGIN GPL 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. + * + * 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) 2008 Blender Foundation. + * All rights reserved. + * + * + * Contributor(s): Blender Foundation + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <stdlib.h> +#include <math.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_listBase.h" +#include "DNA_action_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_windowmanager_types.h" + +#include "BLI_blenlib.h" + +#include "BKE_context.h" +#include "BKE_utildefines.h" + +#include "UI_interface.h" +#include "UI_view2d.h" + +#include "action_intern.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + + +/* ************************** registration - operator types **********************************/ + +void action_operatortypes(void) +{ + /* channels */ + + /* keyframes */ + WM_operatortype_append(ED_ACT_OT_keyframes_clickselect); +} + +/* ************************** registration - keymaps **********************************/ + +static void action_keymap_keyframes (ListBase *keymap) +{ + /* click-select */ + WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, 0, 0); + RNA_boolean_set(WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend_select", 1); + RNA_boolean_set(WM_keymap_add_item(keymap, "ED_ACT_OT_keyframes_clickselect", SELECTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "left_right", 1); +} + +/* --------------- */ + +void action_keymap(wmWindowManager *wm) +{ + ListBase *keymap; + + /* channels */ + keymap= WM_keymap_listbase(wm, "Action_Channels", SPACE_ACTION, 0); + + /* keyframes */ + keymap= WM_keymap_listbase(wm, "Action_Keys", SPACE_ACTION, 0); + action_keymap_keyframes(keymap); +} + diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c new file mode 100644 index 00000000000..050674ee32d --- /dev/null +++ b/source/blender/editors/space_action/action_select.c @@ -0,0 +1,551 @@ +/** + * $Id: editaction.c 17746 2008-12-08 11:19:44Z aligorith $ + * + * ***** BEGIN GPL 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. + * + * 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): Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include <math.h> +#include <stdlib.h> +#include <string.h> +#include <float.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "DNA_listBase.h" +#include "DNA_action_types.h" +#include "DNA_armature_types.h" +#include "DNA_camera_types.h" +#include "DNA_curve_types.h" +#include "DNA_ipo_types.h" +#include "DNA_object_types.h" +#include "DNA_screen_types.h" +#include "DNA_scene_types.h" +#include "DNA_space_types.h" +#include "DNA_constraint_types.h" +#include "DNA_key_types.h" +#include "DNA_lamp_types.h" +#include "DNA_material_types.h" +#include "DNA_userdef_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_windowmanager_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "BKE_action.h" +#include "BKE_depsgraph.h" +#include "BKE_ipo.h" +#include "BKE_key.h" +#include "BKE_material.h" +#include "BKE_object.h" +#include "BKE_context.h" +#include "BKE_utildefines.h" + +#include "UI_view2d.h" + +#include "ED_anim_api.h" +#include "ED_keyframing.h" +#include "ED_keyframes_draw.h" +#include "ED_keyframes_edit.h" +#include "ED_screen.h" +#include "ED_space_api.h" + +#include "WM_api.h" +#include "WM_types.h" + +/* ************************************************************************** */ +/* GENERAL STUFF */ + +#if 0 +/* this function finds the channel that mouse is floating over */ +void *get_nearest_act_channel (short mval[], short *ret_type, void **owner) +{ + ListBase act_data = {NULL, NULL}; + bActListElem *ale; + void *data; + short datatype; + int filter; + + int clickmin, clickmax; + float x,y; + + /* init 'owner' return val */ + *owner= NULL; + + /* determine what type of data we are operating on */ + data = get_action_context(&datatype); + if (data == NULL) { + *ret_type= ACTTYPE_NONE; + return NULL; + } + + areamouseco_to_ipoco(G.v2d, mval, &x, &y); + clickmin = (int) (((CHANNELHEIGHT/2) - y) / (CHANNELHEIGHT+CHANNELSKIP)); + clickmax = clickmin; + + if (clickmax < 0) { + *ret_type= ACTTYPE_NONE; + return NULL; + } + + /* filter data */ + filter= (ACTFILTER_FORDRAWING | ACTFILTER_VISIBLE | ACTFILTER_CHANNELS); + actdata_filter(&act_data, filter, data, datatype); + + for (ale= act_data.first; ale; ale= ale->next) { + if (clickmax < 0) + break; + if (clickmin <= 0) { + /* found match */ + *ret_type= ale->type; + data= ale->data; + + /* if an 'ID' has been set, this takes presidence as owner (for dopesheet) */ + if (datatype == ACTCONT_DOPESHEET) { + /* return pointer to ID as owner instead */ + if (ale->id) + *owner= ale->id; + else + *owner= ale->owner; + } + else { + /* just use own owner */ + *owner= ale->owner; + } + + BLI_freelistN(&act_data); + + return data; + } + --clickmin; + --clickmax; + } + + /* cleanup */ + BLI_freelistN(&act_data); + + *ret_type= ACTTYPE_NONE; + return NULL; +} +#endif + +/* used only by mouse_action. It is used to find the location of the nearest + * keyframe to where the mouse clicked, + */ +static void *get_nearest_action_key (bAnimContext *ac, int mval[2], float *selx, short *sel, short *ret_type, bActionChannel **par) +{ + ListBase anim_data = {NULL, NULL}; + ListBase anim_keys = {NULL, NULL}; + bAnimListElem *ale; + ActKeyColumn *ak; + View2D *v2d= &ac->ar->v2d; + int filter; + + rctf rectf; + void *data = NULL; + float xmin, xmax, x, y; + int clickmin, clickmax; + short found = 0; + + /* action-channel */ + *par= NULL; + + UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); + clickmin = (int) (((ACHANNEL_HEIGHT_HALF) - y) / (ACHANNEL_STEP)); // xxx max y-co (first) is -ACHANNEL_HEIGHT + clickmax = clickmin; + + /* x-range to check is +/- 7 on either side of mouse click (size of keyframe icon) */ + UI_view2d_region_to_view(v2d, mval[0]-7, mval[1], &rectf.xmin, &rectf.ymin); + UI_view2d_region_to_view(v2d, mval[0]+7, mval[1], &rectf.xmax, &rectf.ymax); + + if (clickmax < 0) { + *ret_type= ANIMTYPE_NONE; + return NULL; + } + + /* filter data */ + filter= (ANIMFILTER_FORDRAWING | ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS); + ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype); + + for (ale= anim_data.first; ale; ale= ale->next) { + if (clickmax < 0) + break; + if (clickmin <= 0) { + /* found match - must return here... */ + Object *nob= ANIM_nla_mapping_get(ac, ale); + + /* apply NLA-scaling correction? */ + if (nob) { + xmin= get_action_frame(nob, rectf.xmin); + xmax= get_action_frame(nob, rectf.xmax); + } + else { + xmin= rectf.xmin; + xmax= rectf.xmax; + } + + /* make list of keyframes */ + if (ale->key_data) { + switch (ale->datatype) { + case ALE_OB: + { + Object *ob= (Object *)ale->key_data; + ob_to_keylist(ob, &anim_keys, NULL, NULL); + } + break; + case ALE_ACT: + { + bAction *act= (bAction *)ale->key_data; + action_to_keylist(act, &anim_keys, NULL, NULL); + } + break; + case ALE_IPO: + { + Ipo *ipo= (Ipo *)ale->key_data; + ipo_to_keylist(ipo, &anim_keys, NULL, NULL); + } + break; + case ALE_ICU: + { + IpoCurve *icu= (IpoCurve *)ale->key_data; + icu_to_keylist(icu, &anim_keys, NULL, NULL); + } + break; + } + } + else if (ale->type == ANIMTYPE_GROUP) { + bActionGroup *agrp= (bActionGroup *)ale->data; + agroup_to_keylist(agrp, &anim_keys, NULL, NULL); + } + else if (ale->type == ANIMTYPE_GPDATABLOCK) { + /* cleanup */ + BLI_freelistN(&anim_data); + + /* this channel currently doens't have any keyframes... must ignore! */ + *ret_type= ANIMTYPE_NONE; + return NULL; + } + else if (ale->type == ANIMTYPE_GPLAYER) { + bGPDlayer *gpl= (bGPDlayer *)ale->data; + gpl_to_keylist(gpl, &anim_keys, NULL, NULL); + } + + /* loop through keyframes, finding one that was clicked on */ + for (ak= anim_keys.first; ak; ak= ak->next) { + if (IN_RANGE(ak->cfra, xmin, xmax)) { + *selx= ak->cfra; + found= 1; + break; + } + } + /* no matching keyframe found - set to mean frame value so it doesn't actually select anything */ + if (found == 0) + *selx= ((xmax+xmin) / 2); + + /* figure out what to return */ + if (ac->datatype == ANIMCONT_ACTION) { + *par= ale->owner; /* assume that this is an action channel */ + *ret_type= ale->type; + data = ale->data; + } + else if (ac->datatype == ANIMCONT_SHAPEKEY) { + data = ale->key_data; + *ret_type= ANIMTYPE_ICU; + } + else if (ac->datatype == ANIMCONT_DOPESHEET) { + data = ale->data; + *ret_type= ale->type; + } + else if (ac->datatype == ANIMCONT_GPENCIL) { + data = ale->data; + *ret_type= ANIMTYPE_GPLAYER; + } + + /* cleanup tempolary lists */ + BLI_freelistN(&anim_keys); + anim_keys.first = anim_keys.last = NULL; + + BLI_freelistN(&anim_data); + + return data; + } + --clickmin; + --clickmax; + } + + /* cleanup */ + BLI_freelistN(&anim_data); + + *ret_type= ANIMTYPE_NONE; + return NULL; +} + +/* ************************************************************************** */ +/* CHANNEL STUFF */ + +/* ************************************************************************** */ +/* KEYFRAMES STUFF */ + +/* ******************** Column Select Operator **************************** */ + +/* ******************** Mouse-Click Select Operator *********************** */ +/* This operator works in one of four ways: + * - main area + * -> 1) without alt-key - selects keyframe that was under mouse position + * -> 2) with alt-key - only those keyframes on same side of current frame + * - 3) horizontal scroller (*) - select all keyframes in frame (err... maybe integrate this with column select only)? + * - 4) vertical scroller (*) - select all keyframes in channel + * + * (*) - these are not obviously presented in UI. We need to find a new way to showcase them. + */ + +/* option 1) select keyframe directly under mouse */ +static void mouse_action_keys (bAnimContext *ac, int mval[2], short selectmode) +{ + Object *ob= NULL; + bDopeSheet *ads= NULL; + bAction *act= NULL; + bActionGroup *agrp= NULL; + bActionChannel *achan= NULL; + bConstraintChannel *conchan= NULL; + Ipo *ipo= NULL; + IpoCurve *icu= NULL; + bGPdata *gpd = NULL; + bGPDlayer *gpl = NULL; + + void *act_channel; + short sel, act_type = 0; + float selx = 0.0f, selxa; + + /* determine what type of data we are operating on */ + if (ac->datatype == ANIMCONT_ACTION) + act= (bAction *)ac->data; + else if (ac->datatype == ANIMCONT_DOPESHEET) + ads= (bDopeSheet *)ac->data; + else if (ac->datatype == ANIMCONT_GPENCIL) + gpd= (bGPdata *)ac->data; + + act_channel= get_nearest_action_key(ac, mval, &selx, &sel, &act_type, &achan); + if (act_channel) { + /* must have been a channel */ + switch (act_type) { + case ANIMTYPE_ICU: + icu= (IpoCurve *)act_channel; + break; + case ANIMTYPE_CONCHAN: + conchan= (bConstraintChannel *)act_channel; + break; + case ANIMTYPE_ACHAN: + achan= (bActionChannel *)act_channel; + break; + case ANIMTYPE_GROUP: + agrp= (bActionGroup *)act_channel; + break; + case ANIMTYPE_DSMAT: + ipo= ((Material *)act_channel)->ipo; + break; + case ANIMTYPE_DSLAM: + ipo= ((Lamp *)act_channel)->ipo; + break; + case ANIMTYPE_DSCAM: + ipo= ((Camera *)act_channel)->ipo; + break; + case ANIMTYPE_DSCUR: + ipo= ((Curve *)act_channel)->ipo; + break; + case ANIMTYPE_DSSKEY: + ipo= ((Key *)act_channel)->ipo; + break; + case ANIMTYPE_FILLACTD: + act= (bAction *)act_channel; + break; + case ANIMTYPE_FILLIPOD: + ipo= ((Object *)act_channel)->ipo; + break; + case ANIMTYPE_OBJECT: + ob= ((Base *)act_channel)->object; + break; + case ANIMTYPE_GPLAYER: + gpl= (bGPDlayer *)act_channel; + break; + default: + return; + } + + if (selectmode == SELECT_REPLACE) { + selectmode = SELECT_ADD; + + //deselect_action_keys(0, 0); // XXX fixme + + if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET)) { + //deselect_action_channels(0); + + /* Highlight either an Action-Channel or Action-Group */ + if (achan) { + achan->flag |= ACHAN_SELECTED; + //hilight_channel(act, achan, 1); + //select_poseelement_by_name(achan->name, 2); /* 2 is activate */ + } + else if (agrp) { + agrp->flag |= AGRP_SELECTED; + //set_active_actiongroup(act, agrp, 1); + } + } + else if (ac->datatype == ANIMCONT_GPENCIL) { + //deselect_action_channels(0); + + /* Highlight gpencil layer */ + gpl->flag |= GP_LAYER_SELECT; + //gpencil_layer_setactive(gpd, gpl); + } + } + + if (icu) + select_icu_key(ac->scene, icu, selx, selectmode); + else if (ipo) + select_ipo_key(ac->scene, ipo, selx, selectmode); + else if (conchan) + select_ipo_key(ac->scene, conchan->ipo, selx, selectmode); + else if (achan) + select_ipo_key(ac->scene, achan->ipo, selx, selectmode); + else if (agrp) { + for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) { + select_ipo_key(ac->scene, achan->ipo, selx, selectmode); + + for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) + select_ipo_key(ac->scene, conchan->ipo, selx, selectmode); + } + } + else if (act) { + for (achan= act->chanbase.first; achan; achan= achan->next) { + select_ipo_key(ac->scene, achan->ipo, selx, selectmode); + + for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) + select_ipo_key(ac->scene, conchan->ipo, selx, selectmode); + } + } + else if (ob) { + if (ob->ipo) + select_ipo_key(ac->scene, ob->ipo, selx, selectmode); + + if (ob->action) { + selxa= get_action_frame(ob, selx); + + for (achan= ob->action->chanbase.first; achan; achan= achan->next) { + select_ipo_key(ac->scene, achan->ipo, selxa, selectmode); + + for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) + select_ipo_key(ac->scene, conchan->ipo, selxa, selectmode); + } + } + + for (conchan=ob->constraintChannels.first; conchan; conchan=conchan->next) + select_ipo_key(ac->scene, conchan->ipo, selx, selectmode); + } + //else if (gpl) + // select_gpencil_frame(gpl, (int)selx, selectmode); + } +} + +/* ------------------- */ + +static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *event) +{ + bAnimContext ac; + ARegion *ar; + short in_scroller, selectmode; + int mval[2]; + + puts("Action click select invoke"); + + /* get editor data */ + if ((ANIM_animdata_get_context(C, &ac) == 0) || (ac.data == NULL)) + return OPERATOR_CANCELLED; + + /* get useful pointers from animation context data */ + ar= ac.ar; + + /* get mouse coordinates (in region coordinates) */ + mval[0]= (event->x - ar->winrct.xmin); + mval[1]= (event->y - ar->winrct.ymin); + + /* check where in view mouse is */ + in_scroller = UI_view2d_mouse_in_scrollers(C, &ar->v2d, event->x, event->y); + + /* select mode is either replace (deselect all, then add) or add/extend */ + if (RNA_boolean_get(op->ptr, "extend_select")) + selectmode= SELECT_ADD; + else + selectmode= SELECT_REPLACE; + + /* check which scroller mouse is in, and figure out how to handle this */ + if (in_scroller == 'h') { + /* horizontal - column select in current frame */ + // FIXME.... todo + } + else if (in_scroller == 'v') { + /* vertical - row select in current channel */ + // FIXME... + } + else if (RNA_boolean_get(op->ptr, "left_right")) { + /* select all keys on same side of current frame as mouse */ + + } + else { + /* select keyframe under mouse */ + mouse_action_keys(&ac, mval, selectmode); + // XXX activate transform... + } + + /* set notifier tha things have changed */ + ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead! + + return OPERATOR_FINISHED; +} + +void ED_ACT_OT_keyframes_clickselect (wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Mouse Select Keys"; + ot->idname= "ED_ACT_OT_keyframes_clickselect"; + + /* api callbacks */ + ot->invoke= actkeys_clickselect_invoke; + //ot->poll= ED_operator_areaactive; + + /* id-props */ + RNA_def_property(ot->srna, "left_right", PROP_BOOLEAN, PROP_NONE); // ALTKEY + RNA_def_property(ot->srna, "extend_select", PROP_BOOLEAN, PROP_NONE); // SHIFTKEY +} + +/* ************************************************************************** */ diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 7d6a4804dec..2d600bfe747 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -159,7 +159,7 @@ static void action_main_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "Action", SPACE_ACTION, 0); /* XXX weak? */ + keymap= WM_keymap_listbase(wm, "Action_Keys", SPACE_ACTION, 0); /* XXX weak? */ WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } @@ -214,16 +214,6 @@ static void action_main_area_draw(const bContext *C, ARegion *ar) UI_view2d_scrollers_free(scrollers); } -void action_operatortypes(void) -{ - -} - -void action_keymap(struct wmWindowManager *wm) -{ - -} - /* add handlers, stuff you only do once or on area/region changes */ static void action_channel_area_init(wmWindowManager *wm, ARegion *ar) { @@ -232,7 +222,7 @@ static void action_channel_area_init(wmWindowManager *wm, ARegion *ar) UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_LIST, ar->winx, ar->winy); /* own keymap */ - keymap= WM_keymap_listbase(wm, "Action", SPACE_ACTION, 0); /* XXX weak? */ + keymap= WM_keymap_listbase(wm, "Action_Channels", SPACE_ACTION, 0); /* XXX weak? */ WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct); } @@ -298,6 +288,11 @@ static void action_header_area_draw(const bContext *C, ARegion *ar) static void action_main_area_listener(ARegion *ar, wmNotifier *wmn) { /* context changes */ + switch(wmn->type) { + case WM_NOTE_MARKERS_CHANGED: + ED_region_tag_redraw(ar); + break; + } } /* only called once, from space/spacetypes.c */ |