NLA Editor: Swap Strips (Alt-F) and Bugfixes
authorJoshua Leung <aligorith@gmail.com>
Tue, 18 Jan 2011 23:38:36 +0000 (23:38 +0000)
committerJoshua Leung <aligorith@gmail.com>
Tue, 18 Jan 2011 23:38:36 +0000 (23:38 +0000)
1) Added a new operator to swap the order of strips within a track
(Alt-F).
This makes it possible to select two strips (or more precisely, two
islands of consecutive + selected strips) in a single track and change
the order in which the appear without needing a extra tracks to
perform the move through.

As usual, the non-overlapping rules apply, so there may be some cases
where swapping in this way is not possible without adjusting the
intermediate strips first manually. Otherwise, everything just gets
too tricky to manage deciding what adjustments should be done to the
obstructing strips to make a fit.

2) Freeing meta-strips didn't free their local data properly (i.e.
modifiers they may have had).

3) Adding strips to tracks, where the endframes for the strips
overlapped would cause problems with incorrect ordering of strips. I
still need to double-check whether evaluation works ok in this case...

release/scripts/ui/space_nla.py
source/blender/blenkernel/intern/nla.c
source/blender/editors/space_nla/nla_edit.c
source/blender/editors/space_nla/nla_intern.h
source/blender/editors/space_nla/nla_ops.c

index 5994b1dcc011b2ebc2cab030adba467f5c882923..2dc3474ec9c2ba7d6218eaa6be9a9d36ef6cb15c 100644 (file)
@@ -139,6 +139,7 @@ class NLA_MT_edit(bpy.types.Menu):
         layout.operator("nla.clear_scale")
 
         layout.separator()
+        layout.operator("nla.swap")
         layout.operator("nla.move_up")
         layout.operator("nla.move_down")
 
index 595614ef1e79e6d3aab80d0f10daa2ec5d82c009..ea2948f305e0a583d907e5f17ebf22d38194149a 100644 (file)
@@ -514,7 +514,7 @@ short BKE_nlastrips_has_space (ListBase *strips, float start, float end)
                /* if start frame of strip is past the target end-frame, that means that
                 * we've gone past the window we need to check for, so things are fine
                 */
-               if (strip->start > end)
+               if (strip->start >= end)
                        return 1;
                
                /* if the end of the strip is greater than either of the boundaries, the range
@@ -591,7 +591,7 @@ short BKE_nlastrips_add_strip (ListBase *strips, NlaStrip *strip)
        /* find the right place to add the strip to the nominated track */
        for (ns= strips->first; ns; ns= ns->next) {
                /* if current strip occurs after the new strip, add it before */
-               if (ns->start > strip->end) {
+               if (ns->start >= strip->end) {
                        BLI_insertlinkbefore(strips, ns, strip);
                        not_added= 0;
                        break;
@@ -683,7 +683,7 @@ void BKE_nlastrips_clear_metastrip (ListBase *strips, NlaStrip *strip)
        }
        
        /* free the meta-strip now */
-       BLI_freelinkN(strips, strip);
+       free_nlastrip(strips, strip);
 }
 
 /* Remove meta-strips (i.e. flatten the list of strips) from the top-level of the list of strips
index d1417d69ae3e3224d7ef439ae81a02564895349a..921660b0b8bfdcbfcd1909173c90abd8da594942 100644 (file)
@@ -1006,6 +1006,164 @@ void NLA_OT_mute_toggle (wmOperatorType *ot)
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
+/* ******************** Swap Strips Operator ************************** */
+/* Tries to exchange strips within their owner tracks */
+
+static int nlaedit_swap_exec (bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+               
+       /* get a list of the editable tracks being shown in the NLA */
+       filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_FOREDIT);
+       ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+       
+       /* consider each track in turn */
+       for (ale= anim_data.first; ale; ale= ale->next) {
+               NlaTrack *nlt= (NlaTrack *)ale->data;
+               
+               NlaStrip *strip, *stripN=NULL;
+               NlaStrip *sa=NULL, *sb=NULL;
+               
+               /* make temporary metastrips so that entire islands of selections can be moved around */
+               BKE_nlastrips_make_metas(&nlt->strips, 1);
+               
+               /* special case: if there is only 1 island (i.e. temp meta BUT NOT unselected/normal/normal-meta strips) left after this, 
+                * and this island has two strips inside it, then we should be able to just swap these still...
+                */
+               if (nlt->strips.first == nlt->strips.last) {
+                       NlaStrip *mstrip = (NlaStrip *)nlt->strips.first;
+                       
+                       if ((mstrip->flag & NLASTRIP_FLAG_TEMP_META) && (BLI_countlist(&mstrip->strips) == 2)) 
+                       {
+                               /* remove this temp meta, so that we can see the strips inside */
+                               BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
+                       }
+               }
+               
+               /* get two selected strips only (these will be metas due to prev step) to operate on
+                *      - only allow swapping 2, as with more the context becomes unclear
+                */
+               for (strip = nlt->strips.first; strip; strip = stripN) {
+                       stripN = strip->next;
+                       
+                       if (strip->flag & NLASTRIP_FLAG_SELECT) {
+                               /* first or second strip? */
+                               if (sa == NULL) {
+                                       /* store as first */
+                                       sa = strip;
+                               }
+                               else if (sb == NULL) {
+                                       /* store as second */
+                                       sb = strip;
+                               }
+                               else {
+                                       /* too many selected */
+                                       break;
+                               }
+                       }
+               }
+               
+               if (strip) {
+                       /* too many selected warning */
+                       BKE_reportf(op->reports, RPT_WARNING, 
+                               "Too many clusters of strips selected in NLA Track (%s). Needs exactly 2 to be selected.",
+                               nlt->name);
+               }
+               else if (sa == NULL) {
+                       /* no warning as this is just a common case, and it may get annoying when doing multiple tracks */
+               }
+               else if (sb == NULL) {
+                       /* too few selected warning */
+                       BKE_reportf(op->reports, RPT_WARNING,
+                               "Too few clusters of strips selected in NLA Track (%s). Needs exactly 2 to be selected.",
+                               nlt->name);
+               }
+               else {
+                       float nsa[2], nsb[2];
+                       
+                       /* remove these strips from the track, so that we can test if they can fit in the proposed places */
+                       BLI_remlink(&nlt->strips, sa);
+                       BLI_remlink(&nlt->strips, sb);
+                       
+                       /* calculate new extents for strips */
+                               /* a --> b */
+                       nsa[0] = sb->start;
+                       nsa[1] = sb->start + (sa->end - sa->start);
+                               /* b --> a */
+                       nsb[0] = sa->start;
+                       nsb[1] = sa->start + (sb->end - sb->start);
+                       
+                       /* check if the track has room for the strips to be swapped */
+                       if (BKE_nlastrips_has_space(&nlt->strips, nsa[0], nsa[1]) && 
+                               BKE_nlastrips_has_space(&nlt->strips, nsb[0], nsb[1]))
+                       {
+                               /* set new extents for strips then */
+                               sa->start = nsa[0];
+                               sa->end   = nsa[1];
+                               BKE_nlameta_flush_transforms(sa);
+                               
+                               sb->start = nsb[0];
+                               sb->end   = nsb[1];
+                               BKE_nlameta_flush_transforms(sb);
+                       }
+                       else {
+                               /* not enough room to swap, so show message */
+                               if ((sa->flag & NLASTRIP_FLAG_TEMP_META) || (sb->flag & NLASTRIP_FLAG_TEMP_META)) {
+                                       BKE_report(op->reports, RPT_WARNING,
+                                               "Cannot swap selected strips as they will not be able to fit in their new places");
+                               }
+                               else {
+                                       BKE_reportf(op->reports, RPT_WARNING,   
+                                               "Cannot swap '%s' and '%s' as one or both will not be able to fit in their new places",
+                                               sa->name, sb->name);
+                               }
+                       }
+                       
+                       /* add strips back to track now */
+                       BKE_nlatrack_add_strip(nlt, sa);
+                       BKE_nlatrack_add_strip(nlt, sb);
+               }
+               
+               /* clear (temp) metastrips */
+               BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
+       }
+       
+       /* free temp data */
+       BLI_freelistN(&anim_data);
+       
+       /* refresh auto strip properties */
+       ED_nla_postop_refresh(&ac);
+       
+       /* set notifier that things have changed */
+       WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
+       
+       /* done */
+       return OPERATOR_FINISHED;
+}
+
+void NLA_OT_swap (wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Swap Strips";
+       ot->idname= "NLA_OT_swap";
+       ot->description= "Swap order of selected strips within tracks";
+       
+       /* api callbacks */
+       ot->exec= nlaedit_swap_exec;
+       ot->poll= nlaop_poll_tweakmode_off;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
 /* ******************** Move Strips Up Operator ************************** */
 /* Tries to move the selected strips into the track above if possible. */
 
index 5bf81658fdf0a3bc13c3fbcf5320510e37917e76..b2ff0e107b3e27f8f6a53810eb6186b0bfd71ca2 100644 (file)
@@ -100,6 +100,7 @@ void NLA_OT_split(wmOperatorType *ot);
 
 void NLA_OT_mute_toggle(wmOperatorType *ot);
 
+void NLA_OT_swap(wmOperatorType *ot);
 void NLA_OT_move_up(wmOperatorType *ot);
 void NLA_OT_move_down(wmOperatorType *ot);
 
index c5d6cde62c6d3953a47737dd993d610d7e44262d..6a32f02c8adffc30ce61d9a4b47dd28da8e97cea 100644 (file)
@@ -139,6 +139,7 @@ void nla_operatortypes(void)
        
        WM_operatortype_append(NLA_OT_mute_toggle);
        
+       WM_operatortype_append(NLA_OT_swap);
        WM_operatortype_append(NLA_OT_move_up);
        WM_operatortype_append(NLA_OT_move_down);
        
@@ -225,6 +226,9 @@ static void nla_keymap_main (wmKeyConfig *keyconf, wmKeyMap *keymap)
                /* toggles */
        WM_keymap_add_item(keymap, "NLA_OT_mute_toggle", HKEY, KM_PRESS, 0, 0);
        
+               /* swap */
+       WM_keymap_add_item(keymap, "NLA_OT_swap", FKEY, KM_PRESS, KM_ALT, 0);
+               
                /* move up */
        WM_keymap_add_item(keymap, "NLA_OT_move_up", PAGEUPKEY, KM_PRESS, 0, 0);
                /* move down */