diff options
author | Joshua Leung <aligorith@gmail.com> | 2008-12-23 14:02:39 +0300 |
---|---|---|
committer | Joshua Leung <aligorith@gmail.com> | 2008-12-23 14:02:39 +0300 |
commit | 87c05f7836e5b646e0053bd23f138bc36ab18773 (patch) | |
tree | 97bd56f7e3f9a28cf544dc904ba0790697764a5b /source | |
parent | 58da63cd3efb8c4a1789f0a49afa144c40c551b0 (diff) |
2.5 Action Editor - Big WIP Commit
* Brought back backend for editing keyframes IPO/IPO-Curves. Did some refactoring work here that will still have to be verified when operators using them are added.
* Animation channel filtering code now returns the number of channels filtered (for Action Editor to set totrect of channels - TODO still!)
* View2D - made function to check if mouse is in View2D scrollers an API function
* Renamed keyframe related files. The old names were too clumsy.
* Started porting click-select operators for Action Editor. These don't work currently, as the events are being stolen by the markers. This needs to be fixed ASAP.
Diffstat (limited to 'source')
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 */ |