NLA and IPO now have the "AfterTrans Keyframe" option that prevents the creation...
[blender.git] / source / blender / src / transform_conversions.c
index 6636c435b8c20fa249d673e56b978d2b0703b60c..e42eedee1f72a0446e1db82e128fd45a75a65802 100644 (file)
@@ -144,6 +144,8 @@ extern ListBase editelems;
 
 /* local function prototype - for Object/Bone Constraints */
 static short constraints_list_needinv(TransInfo *t, ListBase *list);
+/* local function prototype - for finding number of keyframes that are selected for editing */
+static int count_ipo_keys(Ipo *ipo, char side, float cfra);
 
 /* ************************** Functions *************************** */
 
@@ -2490,6 +2492,93 @@ static void posttrans_action_clean (bAction *act)
        BLI_freelistN(&act_data);
 }
 
+/* Called by special_aftertrans_update to make sure selected keyframes replace
+ * any other keyframes which may reside on that frame (that is not selected).
+ * remake_all_ipos should have already been called 
+ */
+static void posttrans_nla_clean (TransInfo *t)
+{
+       Base *base;
+       Object *ob;
+       bActionStrip *strip;
+       bActionChannel *achan;
+       bConstraintChannel *conchan;
+       float cfra;
+       char side;
+       int i;
+       
+       /* 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';
+       }
+       
+       /* only affect keyframes */
+       for (base=G.scene->base.first; base; base=base->next) {
+               ob= base->object;
+               
+               /* Check object ipos */
+               i= count_ipo_keys(ob->ipo, side, CFRA);
+               if (i) posttrans_ipo_clean(ob->ipo);
+               
+               /* Check object constraint ipos */
+               for (conchan=ob->constraintChannels.first; conchan; conchan=conchan->next) {
+                       i= count_ipo_keys(conchan->ipo, side, CFRA);    
+                       if (i) posttrans_ipo_clean(ob->ipo);
+               }
+               
+               /* skip actions and nlastrips if object is collapsed */
+               if (ob->nlaflag & OB_NLA_COLLAPSED)
+                       continue;
+               
+               /* Check action ipos */
+               if (ob->action) {
+                       /* exclude if strip is selected too */
+                       for (strip=ob->nlastrips.first; strip; strip=strip->next) {
+                               if (strip->flag & ACTSTRIP_SELECT) {
+                                       if (strip->act == ob->action)
+                                               break;
+                               }
+                       }
+                       if (strip==NULL) {
+                               cfra = get_action_frame(ob, CFRA);
+                               
+                               for (achan=ob->action->chanbase.first; achan; achan=achan->next) {
+                                       if (EDITABLE_ACHAN(achan)) {
+                                               i= count_ipo_keys(achan->ipo, side, cfra);
+                                               if (i) {
+                                                       actstrip_map_ipo_keys(ob, achan->ipo, 0, 1); 
+                                                       posttrans_ipo_clean(achan->ipo);
+                                                       actstrip_map_ipo_keys(ob, achan->ipo, 1, 1);
+                                               }
+                                               
+                                               /* Check action constraint ipos */
+                                               if (EXPANDED_ACHAN(achan) && FILTER_CON_ACHAN(achan)) {
+                                                       for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next) {
+                                                               if (EDITABLE_CONCHAN(conchan)) {
+                                                                       i = count_ipo_keys(conchan->ipo, side, cfra);
+                                                                       if (i) {
+                                                                               actstrip_map_ipo_keys(ob, conchan->ipo, 0, 1); 
+                                                                               posttrans_ipo_clean(conchan->ipo);
+                                                                               actstrip_map_ipo_keys(ob, conchan->ipo, 1, 1);
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }               
+               }
+       }
+}
+
 /* ----------------------------- */
 
 /* This function tests if a point is on the "mouse" side of the cursor/frame-marking */
@@ -3487,8 +3576,6 @@ void special_aftertrans_update(TransInfo *t)
                        if (key->ipo) {
                                IpoCurve *icu;
                                
-                               
-                               
                                if ( (G.saction->flag & SACTION_NOTRANSKEYCULL)==0 && 
                                     (cancelled == 0) )
                                {
@@ -3507,17 +3594,39 @@ void special_aftertrans_update(TransInfo *t)
                G.saction->flag &= ~SACTION_MOVING;
        }
        else if (t->spacetype == SPACE_NLA) {
+               recalc_all_ipos();      // bad
                synchronize_action_strips();
                
                /* cleanup */
                for (base=G.scene->base.first; base; base=base->next)
                        base->flag &= ~(BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA);
                
-               recalc_all_ipos();      // bad
+               /* after transform, remove duplicate keyframes on a frame that resulted from transform */
+               if ( (G.snla->flag & SNLA_NOTRANSKEYCULL)==0 && 
+                        (cancelled == 0) )
+               {
+                       posttrans_nla_clean(t);
+               }
        }
        else if (t->spacetype == SPACE_IPO) {
                // FIXME! is there any code from the old transform_ipo that needs to be added back? 
                
+               /* after transform, remove duplicate keyframes on a frame that resulted from transform */
+               if (G.sipo->ipo) 
+               {
+                       if ( (G.sipo->flag & SIPO_NOTRANSKEYCULL)==0 && 
+                                (cancelled == 0) )
+                       {
+                               if (NLA_IPO_SCALED) {
+                                       actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 0, 1); 
+                                       posttrans_ipo_clean(G.sipo->ipo);
+                                       actstrip_map_ipo_keys(OBACT, G.sipo->ipo, 1, 1);
+                               }
+                               else 
+                                       posttrans_ipo_clean(G.sipo->ipo);
+                       }
+               }
+               
                /* resetting slow-parents isn't really necessary when editing sequence ipo's */
                if (G.sipo->blocktype==ID_SEQ)
                        resetslowpar= 0;