2.5 Action Editor - Big WIP Commit
authorJoshua Leung <aligorith@gmail.com>
Tue, 23 Dec 2008 11:02:39 +0000 (11:02 +0000)
committerJoshua Leung <aligorith@gmail.com>
Tue, 23 Dec 2008 11:02:39 +0000 (11:02 +0000)
* 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.

16 files changed:
source/blender/editors/animation/anim_draw.c
source/blender/editors/animation/anim_filter.c
source/blender/editors/animation/keyframes_draw.c [moved from source/blender/editors/animation/anim_keyframes_draw.c with 100% similarity]
source/blender/editors/animation/keyframes_edit.c [new file with mode: 0644]
source/blender/editors/animation/keyframing.c [moved from source/blender/editors/animation/anim_keyframing.c with 100% similarity]
source/blender/editors/include/ED_anim_api.h
source/blender/editors/include/ED_keyframes_edit.h [new file with mode: 0644]
source/blender/editors/include/ED_markers.h
source/blender/editors/include/UI_view2d.h
source/blender/editors/interface/view2d.c
source/blender/editors/interface/view2d_ops.c
source/blender/editors/space_action/SConscript
source/blender/editors/space_action/action_intern.h
source/blender/editors/space_action/action_ops.c [new file with mode: 0644]
source/blender/editors/space_action/action_select.c [new file with mode: 0644]
source/blender/editors/space_action/space_action.c

index 3765337f990af6857f98e52a7ff75c9d80a4a711..f89a1eb96b813b6f16c9f5659713a600da246cc1 100644 (file)
@@ -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]);
+                       }
+               }
+       }
+}
+
 /* *************************************************** */
index d4b9f9fff933b5823c3af699670790c20a8c8bba..d1f410474756bb7bee8b1a15f47e92095629b3a3 100644 (file)
@@ -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/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
new file mode 100644 (file)
index 0000000..152d07b
--- /dev/null
@@ -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);
+                       }
+               }
+       }
+}
+
+
index aa1333f3ce7da935c2e4b42291a42170b296973d..efd104081c1c837ff85db99e972d93a6eb479cd4 100644 (file)
@@ -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 (file)
index 0000000..ed3c09c
--- /dev/null
@@ -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 */
index 49f805e4ddbe83ed971cfd0c8e6fcaddca2b9349..001c61c158982447c782bed20fb9ea801ab047f1 100644 (file)
@@ -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); 
index 19054f48dba6229cc02b9fbe9ba5f5290450cc4b..8992e71759c9bc48d7fd62ef61e575dee3963b32 100644 (file)
@@ -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);
index f827d68f697064466b87d14ab092ab1659d72eea..2398f8e2e3522333c03abf76a3bcb74261b8d4c1 100644 (file)
@@ -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;
+}
+
index 132413477f1516b574a67cae4afd063e6a32733c..40017669345cccc27d8c708f8414a31302a5e17e 100644 (file)
 #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) {
index 3d22e8ed5abd3a1aa334a7ccf54d4f6f66a3537c..01684e1c2eeb6e00f1642cad446da0eb32d0ebb8 100644 (file)
@@ -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] )
index 67fdff6190e487a2491170b5f2b0b33c040196c5..ef9ab5a9d66a877deb7997f3be62cbc4887d0e0e 100644 (file)
@@ -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 (file)
index 0000000..9a64a02
--- /dev/null
@@ -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 (file)
index 0000000..050674e
--- /dev/null
@@ -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
+}
+
+/* ************************************************************************** */
index 7d6a4804dec79f836df87d7a9646bdfaf1d11151..2d600bfe7471cd138030e06fc8324eefc6749e3c 100644 (file)
@@ -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 */