Bugfix [#34645] NlaStrip Tweak Mode - No automatic action length sync on exit
authorJoshua Leung <aligorith@gmail.com>
Fri, 26 Apr 2013 13:42:55 +0000 (13:42 +0000)
committerJoshua Leung <aligorith@gmail.com>
Fri, 26 Apr 2013 13:42:55 +0000 (13:42 +0000)
Originally I was thinking of not restoring this functionality (see report for
further details). However, upon rechecking the code, it seems that there was
actually a define set up for this already, but which wasn't actually hooked up
yet. So, this commit basically exposes this option ("Sync Length") which ensures
that when exiting tweak mode on a NLA Strip, that strip instance (and not other
users of the same action) will be updated to include the newly added keyframes.
This option is not enabled by default, and shouldn't really be needed in most
("intended") workflows.

source/blender/blenkernel/intern/nla.c
source/blender/editors/space_nla/nla_buttons.c
source/blender/makesrna/intern/rna_nla.c

index 72d5e73d67b52bf098a86eaf8716e80a79417507..90fdbc5710d24d0403dd8cc74cf2488e9234e506 100644 (file)
@@ -1115,6 +1115,50 @@ short BKE_nlastrip_within_bounds(NlaStrip *strip, float min, float max)
        return 1;
 }
 
+
+/* Ensure that strip doesn't overlap those around it after resizing by offsetting those which follow */
+static void nlastrip_fix_resize_overlaps(NlaStrip *strip)
+{
+       /* next strips - do this first, since we're often just getting longer */
+       if (strip->next) {
+               NlaStrip *nls = strip->next;
+               float offset = 0.0f;
+               
+               if (strip->end > nls->start) {
+                       /* NOTE: need to ensure we don't have a fractional frame offset, even if that leaves a gap,
+                        * otherwise it will be very hard to get rid of later
+                        */
+                       offset = ceilf(strip->end - nls->start);
+                       
+                       /* apply to times of all strips in this direction */
+                       for (; nls; nls = nls->next) {
+                               nls->start += offset;
+                               nls->end   += offset;
+                       }
+               }
+       }
+       
+       /* previous strips - same routine as before */
+       /* NOTE: when strip bounds are recalculated, this is not considered! */
+       if (strip->prev) {
+               NlaStrip *nls = strip->prev;
+               float offset = 0.0f;
+               
+               if (strip->start < nls->end) {
+                       /* NOTE: need to ensure we don't have a fractional frame offset, even if that leaves a gap,
+                        * otherwise it will be very hard to get rid of later
+                        */
+                       offset = ceilf(nls->end - strip->start);
+                       
+                       /* apply to times of all strips in this direction */
+                       for (; nls; nls = nls->prev) {
+                               nls->start -= offset;
+                               nls->end   -= offset;
+                       }
+               }
+       }
+}
+
 /* Recalculate the start and end frames for the current strip, after changing
  * the extents of the action or the mapping (repeats or scale factor) info
  */
@@ -1138,6 +1182,9 @@ void BKE_nlastrip_recalculate_bounds(NlaStrip *strip)
        /* adjust endpoint of strip in response to this */
        if (IS_EQF(mapping, 0.0f) == 0)
                strip->end = (actlen * mapping) + strip->start;
+       
+       /* make sure we don't overlap our neighbours */
+       nlastrip_fix_resize_overlaps(strip);
 }
 
 /* Is the given NLA-strip the first one to occur for the given AnimData block */
@@ -1634,7 +1681,22 @@ void BKE_nla_tweakmode_exit(AnimData *adt)
        if ((adt->flag & ADT_NLA_EDIT_ON) == 0)
                return;
                
-       /* TODO: need to sync the user-strip with the new state of the action! */
+       /* sync the length of the user-strip with the new state of the action
+        * but only if the user has explicitly asked for this to happen
+        * (see [#34645] for things to be careful about)
+        */
+       if ((adt->actstrip) && (adt->actstrip->flag & NLASTRIP_FLAG_SYNC_LENGTH)) {
+               strip = adt->actstrip;
+               
+               /* must be action-clip only (transitions don't have scale) */
+               if ((strip->type == NLASTRIP_TYPE_CLIP) && (strip->act)) {
+                       /* recalculate the length of the action */
+                       calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
+                       
+                       /* adjust the strip extents in response to this */
+                       BKE_nlastrip_recalculate_bounds(strip);
+               }
+       }
 
        /* for all Tracks, clear the 'disabled' flag
         * for all Strips, clear the 'tweak-user' flag
index 3a9336e7acc9f44cb9f94ba201155ab10f7bde31..4678c46b45ff3165a25521d6d86c9d9f99559a9c 100644 (file)
@@ -410,7 +410,11 @@ static void nla_panel_actclip(const bContext *C, Panel *pa)
        uiItemL(column, IFACE_("Action Extents:"), ICON_NONE);
        uiItemR(column, &strip_ptr, "action_frame_start", 0, IFACE_("Start Frame"), ICON_NONE);
        uiItemR(column, &strip_ptr, "action_frame_end", 0, IFACE_("End Frame"), ICON_NONE);
-       uiItemO(column, NULL, ICON_NONE, "NLA_OT_action_sync_length");
+       
+       // XXX: this layout may actually be too abstract and confusing, and may be better using standard column layout
+       row = uiLayoutRow(layout, FALSE);
+       uiItemR(row, &strip_ptr, "use_sync_length", 0, IFACE_("Sync Length"), ICON_NONE);
+       uiItemO(row, IFACE_("Now"), ICON_FILE_REFRESH, "NLA_OT_action_sync_length");
                
        /* action usage */
        column = uiLayoutColumn(layout, TRUE);
index 3bf6c11d9359e7c5d5206614d498aae993f5ec0b..399131bbd6153f6bce41b0bf406781c725f503a8 100644 (file)
@@ -517,13 +517,13 @@ static void rna_def_nlastrip(BlenderRNA *brna)
        prop = RNA_def_property(srna, "action_frame_start", PROP_FLOAT, PROP_TIME);
        RNA_def_property_float_sdna(prop, NULL, "actstart");
        RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_action_start_frame_set", NULL);
-       RNA_def_property_ui_text(prop, "Action Start Frame", "");
+       RNA_def_property_ui_text(prop, "Action Start Frame", "First frame from action to use");
        RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
        
        prop = RNA_def_property(srna, "action_frame_end", PROP_FLOAT, PROP_TIME);
        RNA_def_property_float_sdna(prop, NULL, "actend");
        RNA_def_property_float_funcs(prop, NULL, "rna_NlaStrip_action_end_frame_set", NULL);
-       RNA_def_property_ui_text(prop, "Action End Frame", "");
+       RNA_def_property_ui_text(prop, "Action End Frame", "Last frame from action to use");
        RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
        
        /* Action Reuse */
@@ -616,8 +616,12 @@ static void rna_def_nlastrip(BlenderRNA *brna)
                                 "automatically determined)");
        RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
        
-       /* TODO:  */
-       /* - sync length */
+       prop = RNA_def_property(srna, "use_sync_length", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_boolean_sdna(prop, NULL, "flag", NLASTRIP_FLAG_SYNC_LENGTH);
+       RNA_def_property_ui_text(prop, "Sync Action Length",
+                                "Update range of frames referenced from action "
+                                "after tweaking strip and its keyframes");
+       RNA_def_property_update(prop, NC_ANIMATION | ND_NLA, NULL); /* this will do? */
 }
 
 static void rna_api_nlatrack_strips(BlenderRNA *brna, PropertyRNA *cprop)