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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorJoshua Leung <aligorith@gmail.com>2008-12-23 14:02:39 +0300
committerJoshua Leung <aligorith@gmail.com>2008-12-23 14:02:39 +0300
commit87c05f7836e5b646e0053bd23f138bc36ab18773 (patch)
tree97bd56f7e3f9a28cf544dc904ba0790697764a5b /source
parent58da63cd3efb8c4a1789f0a49afa144c40c551b0 (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')
-rw-r--r--source/blender/editors/animation/anim_draw.c35
-rw-r--r--source/blender/editors/animation/anim_filter.c207
-rw-r--r--source/blender/editors/animation/keyframes_draw.c (renamed from source/blender/editors/animation/anim_keyframes_draw.c)0
-rw-r--r--source/blender/editors/animation/keyframes_edit.c785
-rw-r--r--source/blender/editors/animation/keyframing.c (renamed from source/blender/editors/animation/anim_keyframing.c)0
-rw-r--r--source/blender/editors/include/ED_anim_api.h11
-rw-r--r--source/blender/editors/include/ED_keyframes_edit.h104
-rw-r--r--source/blender/editors/include/ED_markers.h4
-rw-r--r--source/blender/editors/include/UI_view2d.h4
-rw-r--r--source/blender/editors/interface/view2d.c29
-rw-r--r--source/blender/editors/interface/view2d_ops.c34
-rw-r--r--source/blender/editors/space_action/SConscript2
-rw-r--r--source/blender/editors/space_action/action_intern.h8
-rw-r--r--source/blender/editors/space_action/action_ops.c91
-rw-r--r--source/blender/editors/space_action/action_select.c551
-rw-r--r--source/blender/editors/space_action/space_action.c19
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 */