== "Extend" Transform Mode for Action + NLA Editors ==
authorJoshua Leung <aligorith@gmail.com>
Tue, 6 Nov 2007 11:41:09 +0000 (11:41 +0000)
committerJoshua Leung <aligorith@gmail.com>
Tue, 6 Nov 2007 11:41:09 +0000 (11:41 +0000)
Peach Request:
Now the Action and NLA editors have the "Extend" transform mode first seen in the Sequence Editor. Just use the EKEY to start transforming.

It works like Grab, except it only moves the keyframes/side of NLA-strip that was on the same side of the current-frame marker as the mouse was when transform started.

source/blender/include/BIF_transform.h
source/blender/src/editaction.c
source/blender/src/editnla.c
source/blender/src/header_action.c
source/blender/src/header_nla.c
source/blender/src/transform.c
source/blender/src/transform_conversions.c

index eeb465135de6ef62a9ec99b9be830f6cf2283f97..26900b06c5271695175fd7c76316edd24849af97 100644 (file)
@@ -58,6 +58,7 @@
 #define TFM_TIME_TRANSLATE     19      
 #define TFM_TIME_SLIDE         20
 #define        TFM_TIME_SCALE          21
+#define TFM_TIME_EXTEND                22
 
 /* TRANSFORM CONTEXTS */
 #define CTX_NONE                       0
index 3957b10781449ad2a70876af77f4c7f9f51853a2..48a39875cc2c7bdf5a87f8a1aaf91948486f9ac1 100644 (file)
@@ -739,6 +739,12 @@ void transform_action_keys (int mode, int dummy)
                        Transform();
                }
                        break;
+               case 'e':
+               {
+                       initTransform(TFM_TIME_EXTEND, CTX_NONE);
+                       Transform();
+               }
+               break;
        }
 }
 
@@ -2645,7 +2651,12 @@ void winqreadactionspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                        duplicate_action_keys();
                        }
                        break;
-
+                       
+               case EKEY:
+                       if (mval[0] >= ACTWIDTH) 
+                               transform_action_keys('e', 0);
+                       break;
+               
                case GKEY:
                        if (G.qual & LR_CTRLKEY) {
                                transform_markers('g', 0);
index 13423424f904ea7ce00eb92c0c5cf6f20fc5d028..ec3b1c834e5b395f161401627f64fac0257e8065 100644 (file)
@@ -995,6 +995,12 @@ void transform_nlachannel_keys(int mode, int dummy)
                        Transform();
                }
                        break;
+               case 'e':
+               {
+                       initTransform(TFM_TIME_EXTEND, CTX_NONE);
+                       Transform();
+               }
+                       break;
        }
 }
 
@@ -1791,6 +1797,13 @@ void winqreadnlaspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
                                
                                break;
                                
+                       case EKEY:
+                               if (mval[0] >= NLAWIDTH) {
+                                       transform_nlachannel_keys ('e', 0);
+                                       update_for_newframe_muted();
+                               }
+                               break;
+                               
                        case GKEY:
                                if (mval[0]>=NLAWIDTH) {
                                        if (G.qual & LR_CTRLKEY) {
index c6d1b88c95c4705abd727fa9202bfbf09a0b0a2d..4a803926a94e3a5819dc37df69f0ba97d0d51f04 100644 (file)
@@ -114,7 +114,6 @@ enum {
 enum {
        ACTMENU_KEY_DUPLICATE = 0,
        ACTMENU_KEY_DELETE,
-       ACTMENU_KEY_BAKE,
        ACTMENU_KEY_CLEAN
 };
 
@@ -128,7 +127,8 @@ enum {
 enum {
        ACTMENU_KEY_TRANSFORM_MOVE  = 0,
        ACTMENU_KEY_TRANSFORM_SCALE,
-       ACTMENU_KEY_TRANSFORM_SLIDE
+       ACTMENU_KEY_TRANSFORM_SLIDE,
+       ACTMENU_KEY_TRANSFORM_EXTEND
 };
 
 enum {
@@ -594,6 +594,9 @@ static void do_action_keymenu_transformmenu(void *arg, int event)
                case ACTMENU_KEY_TRANSFORM_SLIDE:
                        transform_action_keys('t', 0);
                        break;
+               case ACTMENU_KEY_TRANSFORM_EXTEND:
+                       transform_action_keys('e', 0);
+                       break;
        }
 
        scrarea_queue_winredraw(curarea);
@@ -611,6 +614,9 @@ static uiBlock *action_keymenu_transformmenu(void *arg_unused)
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
                                         "Grab/Move|G", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0,  
                                         ACTMENU_KEY_TRANSFORM_MOVE, "");
+       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
+                                        "Grab/Extend from Frame|E", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 
+                                        ACTMENU_KEY_TRANSFORM_EXTEND, "");
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, 
                                         "Scale|S", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 0, 
                                         ACTMENU_KEY_TRANSFORM_SCALE, "");
index 3a3d3dfdb497cf809d76d612a1cf4eb3241d21fb..96ea6c3d792168c45fd16f7a14b3abf1161851ec 100644 (file)
@@ -269,12 +269,16 @@ static void do_nla_strip_transformmenu(void *arg, int event)
 {
        switch(event) {
        case 0: /* grab/move */
-               transform_nlachannel_keys ('g', 0);
-                       update_for_newframe_muted();
+               transform_nlachannel_keys('g', 0);
+               update_for_newframe_muted();
                break;
        case 1: /* scale */
-               transform_nlachannel_keys ('s', 0);
-                       update_for_newframe_muted();
+               transform_nlachannel_keys('s', 0);
+               update_for_newframe_muted();
+               break;
+       case 2: /* extend */
+               transform_nlachannel_keys('e', 0);
+               update_for_newframe_muted();
                break;
        }
        allqueue(REDRAWVIEW3D, 0);
@@ -289,8 +293,10 @@ static uiBlock *nla_strip_transformmenu(void *arg_unused)
        uiBlockSetButmFunc(block, do_nla_strip_transformmenu, NULL);
        
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Move|G",            0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 0, "");
+       uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Grab/Extend from Frame|E",       0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
        uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Scale|S",                0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 1, "");
-
+       
+       
        uiBlockSetDirection(block, UI_RIGHT);
        uiTextBoundsBlock(block, 60);
        return block;
index 321a56c5ebda032bab4eb8d0435abe48af24774a..2a7f744f219e1a55086c35eded7d7e299b33cb3b 100644 (file)
@@ -938,6 +938,7 @@ void initTransform(int mode, int context) {
 
        /* EVIL! posemode code can switch translation to rotate when 1 bone is selected. will be removed (ton) */
        /* EVIL2: we gave as argument also texture space context bit... was cleared */
+       /* EVIL3: extend mode for animation editors also switches modes... but is best way to avoid duplicate code */
        mode = Trans.mode;
        
        calculatePropRatio(&Trans);
@@ -1004,6 +1005,10 @@ void initTransform(int mode, int context) {
        case TFM_TIME_SCALE:
                initTimeScale(&Trans);
                break;
+       case TFM_TIME_EXTEND: 
+               /* now that transdata has been made, do like for TFM_TIME_TRANSLATE */
+               initTimeTranslate(&Trans);
+               break;
        }
 }
 
index b0e2d8144e8c27b56cfd32088ff509b3ddd39963..820d79eb809c52e155fffb087d8c621e79236a3d 100644 (file)
 #include "BIF_toolbox.h"
 
 #include "BSE_view.h"
+#include "BSE_drawipo.h"
 #include "BSE_edit.h"
 #include "BSE_editipo.h"
 #include "BSE_editipo_types.h"
@@ -2049,7 +2050,48 @@ void flushTransIpoData(TransInfo *t)
 
 /* ********************* ACTION/NLA EDITOR ****************** */
 
+/* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
+static short FrameOnMouseSide(char side, float frame, float cframe)
+{
+       /* both sides, so it doesn't matter */
+       if (side == 'B') return 1;
+       
+       /* only on the named side */
+       if (side == 'R')
+               return (frame >= cframe) ? 1 : 0;
+       else
+               return (frame <= cframe) ? 1 : 0;
+}
 
+/* fully select selected beztriples, but only include if it's on the right side of cfra */
+static int count_ipo_keys(Ipo *ipo, char side, float cfra)
+{
+       IpoCurve *icu;
+       BezTriple *bezt;
+       int i, count = 0;
+       
+       if (ipo == NULL)
+               return count;
+       
+       /* only include points that occur on the right side of cfra */
+       for (icu= ipo->curve.first; icu; icu= icu->next) {
+               for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
+                       if (bezt->f2) {
+                               /* fully select the other two keys */
+                               bezt->f1 |= 1;
+                               bezt->f3 |= 1;
+                               
+                               /* increment by 3, as there are 3 points (3 * x-coordinates) that need transform */
+                               if (FrameOnMouseSide(side, bezt->vec[1][0], cfra))
+                                       count += 3;
+                       }
+               }
+       }
+       
+       return count;
+}
+
+/* This function assigns the information to transdata */
 static void TimeToTransData(TransData *td, float *time, Object *ob)
 {
        /* memory is calloc'ed, so that should zero everything nicely for us */
@@ -2065,9 +2107,12 @@ static void TimeToTransData(TransData *td, float *time, Object *ob)
 
 /* This function advances the address to which td points to, so it must return
  * the new address so that the next time new transform data is added, it doesn't
- * overwrite the existing ones...  i.e.   td = IpoToTransData(td, ipo, ob);
+ * overwrite the existing ones...  i.e.   td = IpoToTransData(td, ipo, ob, side, cfra);
+ *
+ * The 'side' argument is needed for the extend mode. 'B' = both sides, 'R'/'L' mean only data
+ * on the named side are used. 
  */
-static TransData *IpoToTransData(TransData *td, Ipo *ipo, Object *ob)
+static TransData *IpoToTransData(TransData *td, Ipo *ipo, Object *ob, char side, float cfra)
 {
        IpoCurve *icu;
        BezTriple *bezt;
@@ -2077,18 +2122,21 @@ static TransData *IpoToTransData(TransData *td, Ipo *ipo, Object *ob)
                return td;
        
        for (icu= ipo->curve.first; icu; icu= icu->next) {
-               /* only add selected keyframes (for now, proportional edit is not enabled) */
                for (i=0, bezt=icu->bezt; i < icu->totvert; i++, bezt++) {
+                       /* only add selected keyframes (for now, proportional edit is not enabled) */
                        if (BEZSELECTED(bezt)) {
-                               /* each control point needs to be added separetely */
-                               TimeToTransData(td, bezt->vec[0], ob);
-                               td++;
-                               
-                               TimeToTransData(td, bezt->vec[1], ob);
-                               td++;
-                               
-                               TimeToTransData(td, bezt->vec[2], ob);
-                               td++;
+                               /* only add if on the right 'side' of the current frame */
+                               if (FrameOnMouseSide(side, bezt->vec[1][0], cfra)) {
+                                       /* each control point needs to be added separetely */
+                                       TimeToTransData(td, bezt->vec[0], ob);
+                                       td++;
+                                       
+                                       TimeToTransData(td, bezt->vec[1], ob);
+                                       td++;
+                                       
+                                       TimeToTransData(td, bezt->vec[2], ob);
+                                       td++;
+                               }
                        }       
                }
        }
@@ -2108,6 +2156,8 @@ static void createTransActionData(TransInfo *t)
        int filter;
        
        int count=0;
+       float cfra;
+       char side;
        
        /* determine what type of data we are operating on */
        data = get_action_context(&datatype);
@@ -2120,10 +2170,31 @@ static void createTransActionData(TransInfo *t)
        /* is the action scaled? if so, the it should belong to the active object */
        if (NLA_ACTION_SCALED)
                ob= OBACT;
+               
+       /* which side of the current frame should be allowed */
+       if (t->mode == TFM_TIME_EXTEND) {
+               /* only side on which mouse is gets transformed */
+               float xmouse, ymouse;
+               
+               areamouseco_to_ipoco(G.v2d, t->imval, &xmouse, &ymouse);
+               side = (xmouse > CFRA) ? 'R' : 'L';
+       }
+       else {
+               /* normal transform - both sides of current frame are considered */
+               side = 'B';
+       }
+       
+       /* convert current-frame to action-time (slightly less accurate, espcially under
+        * higher scaling ratios, but is faster than converting all points) 
+        */
+       if (ob) 
+               cfra = get_action_frame(ob, CFRA);
+       else
+               cfra = CFRA;
        
        /* loop 1: fully select ipo-keys and count how many BezTriples are selected */
        for (ale= act_data.first; ale; ale= ale->next)
-               count += fullselect_ipo_keys(ale->key_data);
+               count += count_ipo_keys(ale->key_data, side, cfra);
        
        /* stop if trying to build list if nothing selected */
        if (count == 0) {
@@ -2143,7 +2214,7 @@ static void createTransActionData(TransInfo *t)
        for (ale= act_data.first; ale; ale= ale->next) {
                Ipo *ipo= (Ipo *)ale->key_data;
                
-               td= IpoToTransData(td, ipo, ob);
+               td= IpoToTransData(td, ipo, ob, side, cfra);
        }
        
        /* check if we're supposed to be setting minx/maxx for TimeSlide */
@@ -2178,17 +2249,32 @@ static void createTransNlaData(TransInfo *t)
        
        TransData *td = NULL;
        int count=0, i;
+       float cfra;
+       char side;
+       
+       /* which side of the current frame should be allowed */
+       if (t->mode == TFM_TIME_EXTEND) {
+               /* only side on which mouse is gets transformed */
+               float xmouse, ymouse;
+               
+               areamouseco_to_ipoco(G.v2d, t->imval, &xmouse, &ymouse);
+               side = (xmouse > CFRA) ? 'R' : 'L';
+       }
+       else {
+               /* normal transform - both sides of current frame are considered */
+               side = 'B';
+       }
        
        /* Ensure that partial selections result in beztriple selections */
        for (base=G.scene->base.first; base; base=base->next) {
                /* Check object ipos */
-               i= fullselect_ipo_keys(base->object->ipo);
+               i= count_ipo_keys(base->object->ipo, side, CFRA);
                if (i) base->flag |= BA_HAS_RECALC_OB;
                count += i;
                
                /* Check object constraint ipos */
                for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
-                       count += fullselect_ipo_keys(conchan->ipo);                     
+                       count += count_ipo_keys(conchan->ipo, side, CFRA);                      
                
                /* skip actions and nlastrips if object is collapsed */
                if (base->object->nlaflag & OB_NLA_COLLAPSED)
@@ -2203,9 +2289,11 @@ static void createTransNlaData(TransInfo *t)
                                                break;
                        }
                        if (strip==NULL) {
+                               cfra = get_action_frame(base->object, CFRA);
+                               
                                for (achan=base->object->action->chanbase.first; achan; achan=achan->next) {
                                        if (EDITABLE_ACHAN(achan)) {
-                                               i= fullselect_ipo_keys(achan->ipo);
+                                               i= count_ipo_keys(achan->ipo, side, cfra);
                                                if (i) base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA;
                                                count += i;
                                                
@@ -2213,7 +2301,7 @@ static void createTransNlaData(TransInfo *t)
                                                if (EXPANDED_ACHAN(achan) && FILTER_CON_ACHAN(achan)) {
                                                        for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
                                                                if (EDITABLE_CONCHAN(conchan))
-                                                                       count += fullselect_ipo_keys(conchan->ipo);
+                                                                       count += count_ipo_keys(conchan->ipo, side, cfra);
                                                        }
                                                }
                                        }
@@ -2225,7 +2313,9 @@ static void createTransNlaData(TransInfo *t)
                for (strip=base->object->nlastrips.first; strip; strip=strip->next) {
                        if (strip->flag & ACTSTRIP_SELECT) {
                                base->flag |= BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA;
-                               count += 2;
+                               
+                               if (FrameOnMouseSide(side, strip->start, CFRA)) count++;
+                               if (FrameOnMouseSide(side, strip->end, CFRA)) count++;
                        }
                }
        }
@@ -2243,12 +2333,12 @@ static void createTransNlaData(TransInfo *t)
        for (base=G.scene->base.first; base; base=base->next) {
                /* Manipulate object ipos */
                /*      - no scaling of keyframe times is allowed here  */
-               td= IpoToTransData(td, base->object->ipo, NULL);
+               td= IpoToTransData(td, base->object->ipo, NULL, side, CFRA);
                
                /* Manipulate object constraint ipos */
                /*      - no scaling of keyframe times is allowed here  */
                for (conchan=base->object->constraintChannels.first; conchan; conchan=conchan->next)
-                       td= IpoToTransData(td, conchan->ipo, NULL);
+                       td= IpoToTransData(td, conchan->ipo, NULL, side, CFRA);
                
                /* skip actions and nlastrips if object collapsed */
                if (base->object->nlaflag & OB_NLA_COLLAPSED)
@@ -2265,15 +2355,17 @@ static void createTransNlaData(TransInfo *t)
                        
                        /* can include if no strip found */
                        if (strip==NULL) {
+                               cfra = get_action_frame(base->object, CFRA);
+                               
                                for (achan=base->object->action->chanbase.first; achan; achan=achan->next) {
                                        if (EDITABLE_ACHAN(achan)) {
-                                               td= IpoToTransData(td, achan->ipo, base->object);
+                                               td= IpoToTransData(td, achan->ipo, base->object, side, cfra);
                                                
                                                /* Manipulate action constraint ipos */
                                                if (EXPANDED_ACHAN(achan) && FILTER_CON_ACHAN(achan)) {
                                                        for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
                                                                if (EDITABLE_CONCHAN(conchan))
-                                                                       td= IpoToTransData(td, conchan->ipo, base->object);
+                                                                       td= IpoToTransData(td, conchan->ipo, base->object, side, cfra);
                                                        }
                                                }
                                        }
@@ -2285,13 +2377,16 @@ static void createTransNlaData(TransInfo *t)
                for (strip=base->object->nlastrips.first; strip; strip=strip->next) {
                        if (strip->flag & ACTSTRIP_SELECT) {
                                /* first TransData is the start, second is the end */
-                               td->val = &strip->start;
-                               td->ival = strip->start;
-                               td++;
-                               
-                               td->val = &strip->end;
-                               td->ival = strip->end;
-                               td++;
+                               if (FrameOnMouseSide(side, strip->start, CFRA)) {
+                                       td->val = &strip->start;
+                                       td->ival = strip->start;
+                                       td++;
+                               }
+                               if (FrameOnMouseSide(side, strip->end, CFRA)) {
+                                       td->val = &strip->end;
+                                       td->ival = strip->end;
+                                       td++;
+                               }
                        }
                }
        }