Blender V2.61 - r43446

nla_edit.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
00019  * All rights reserved.
00020  *
00021  * 
00022  * Contributor(s): Joshua Leung (major recode)
00023  *
00024  * ***** END GPL LICENSE BLOCK *****
00025  */
00026 
00032 #include <string.h>
00033 #include <stdio.h>
00034 #include <math.h>
00035 
00036 #include "DNA_anim_types.h"
00037 #include "DNA_object_types.h"
00038 #include "DNA_scene_types.h"
00039 
00040 #include "MEM_guardedalloc.h"
00041 
00042 #include "BLI_blenlib.h"
00043 #include "BLI_math.h"
00044 #include "BLI_rand.h"
00045 #include "BLI_utildefines.h"
00046 
00047 #include "BKE_action.h"
00048 #include "BKE_fcurve.h"
00049 #include "BKE_nla.h"
00050 #include "BKE_context.h"
00051 #include "BKE_main.h"
00052 #include "BKE_report.h"
00053 #include "BKE_screen.h"
00054 
00055 #include "ED_anim_api.h"
00056 #include "ED_keyframes_edit.h"
00057 #include "ED_markers.h"
00058 #include "ED_screen.h"
00059 #include "ED_transform.h"
00060 
00061 #include "RNA_access.h"
00062 #include "RNA_define.h"
00063 #include "RNA_enum_types.h"
00064 
00065 #include "WM_api.h"
00066 #include "WM_types.h"
00067 
00068 #include "UI_interface.h"
00069 #include "UI_resources.h"
00070 #include "UI_view2d.h"
00071 
00072 #include "nla_intern.h" // own include
00073 #include "nla_private.h" // FIXME... maybe this shouldn't be included?
00074 
00075 /* *********************************************** */
00076 /* Utilities exported to other places... */
00077 
00078 /* Perform validation for blending/extend settings */
00079 void ED_nla_postop_refresh (bAnimContext *ac)
00080 {
00081     ListBase anim_data = {NULL, NULL};
00082     bAnimListElem *ale;
00083     short filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FOREDIT);
00084     
00085     /* get blocks to work on */
00086     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00087     
00088     for (ale= anim_data.first; ale; ale= ale->next) {
00089         /* performing auto-blending, extend-mode validation, etc. */
00090         BKE_nla_validate_state(ale->data);
00091     }
00092     
00093     /* free temp memory */
00094     BLI_freelistN(&anim_data);
00095 }
00096 
00097 /* *********************************************** */
00098 /* 'Special' Editing */
00099 
00100 /* ******************** Tweak-Mode Operators ***************************** */
00101 /* 'Tweak mode' allows the action referenced by the active NLA-strip to be edited 
00102  * as if it were the normal Active-Action of its AnimData block. 
00103  */
00104 
00105 static int nlaedit_enable_tweakmode_exec (bContext *C, wmOperator *op)
00106 {
00107     bAnimContext ac;
00108     
00109     ListBase anim_data = {NULL, NULL};
00110     bAnimListElem *ale;
00111     int filter;
00112     int ok=0;
00113     
00114     /* get editor data */
00115     if (ANIM_animdata_get_context(C, &ac) == 0)
00116         return OPERATOR_CANCELLED;
00117         
00118     /* get a list of the AnimData blocks being shown in the NLA */
00119     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
00120     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
00121     
00122     /* if no blocks, popup error? */
00123     if (anim_data.first == NULL) {
00124         BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweakmode for");
00125         return OPERATOR_CANCELLED;
00126     }   
00127     
00128     /* for each AnimData block with NLA-data, try setting it in tweak-mode */
00129     for (ale= anim_data.first; ale; ale= ale->next) {
00130         AnimData *adt= ale->data;
00131         
00132         /* try entering tweakmode if valid */
00133         ok += BKE_nla_tweakmode_enter(adt);
00134     }
00135     
00136     /* free temp data */
00137     BLI_freelistN(&anim_data);
00138     
00139     /* if we managed to enter tweakmode on at least one AnimData block, 
00140      * set the flag for this in the active scene and send notifiers
00141      */
00142     if (ac.scene && ok) {
00143         /* set editing flag */
00144         ac.scene->flag |= SCE_NLA_EDIT_ON;
00145         
00146         /* set notifier that things have changed */
00147         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL);
00148     }
00149     else {
00150         BKE_report(op->reports, RPT_ERROR, "No active strip(s) to enter tweakmode on");
00151         return OPERATOR_CANCELLED;
00152     }
00153     
00154     /* done */
00155     return OPERATOR_FINISHED;
00156 }
00157  
00158 void NLA_OT_tweakmode_enter (wmOperatorType *ot)
00159 {
00160     /* identifiers */
00161     ot->name= "Enter Tweak Mode";
00162     ot->idname= "NLA_OT_tweakmode_enter";
00163     ot->description= "Enter tweaking mode for the action referenced by the active strip";
00164     
00165     /* api callbacks */
00166     ot->exec= nlaedit_enable_tweakmode_exec;
00167     ot->poll= nlaop_poll_tweakmode_off;
00168     
00169     /* flags */
00170     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00171 }
00172 
00173 /* ------------- */
00174 
00175 static int nlaedit_disable_tweakmode_exec (bContext *C, wmOperator *op)
00176 {
00177     bAnimContext ac;
00178     
00179     ListBase anim_data = {NULL, NULL};
00180     bAnimListElem *ale;
00181     int filter;
00182     
00183     /* get editor data */
00184     if (ANIM_animdata_get_context(C, &ac) == 0)
00185         return OPERATOR_CANCELLED;
00186         
00187     /* get a list of the AnimData blocks being shown in the NLA */
00188     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ANIMDATA);
00189     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
00190     
00191     /* if no blocks, popup error? */
00192     if (anim_data.first == NULL) {
00193         BKE_report(op->reports, RPT_ERROR, "No AnimData blocks to enter tweakmode for");
00194         return OPERATOR_CANCELLED;
00195     }   
00196     
00197     /* for each AnimData block with NLA-data, try exitting tweak-mode */
00198     for (ale= anim_data.first; ale; ale= ale->next) {
00199         AnimData *adt= ale->data;
00200         
00201         /* try entering tweakmode if valid */
00202         BKE_nla_tweakmode_exit(adt);
00203     }
00204     
00205     /* free temp data */
00206     BLI_freelistN(&anim_data);
00207     
00208     /* if we managed to enter tweakmode on at least one AnimData block, 
00209      * set the flag for this in the active scene and send notifiers
00210      */
00211     if (ac.scene) {
00212         /* clear editing flag */
00213         ac.scene->flag &= ~SCE_NLA_EDIT_ON;
00214         
00215         /* set notifier that things have changed */
00216         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA_ACTCHANGE, NULL);
00217     }
00218     
00219     /* done */
00220     return OPERATOR_FINISHED;
00221 }
00222  
00223 void NLA_OT_tweakmode_exit (wmOperatorType *ot)
00224 {
00225     /* identifiers */
00226     ot->name= "Exit Tweak Mode";
00227     ot->idname= "NLA_OT_tweakmode_exit";
00228     ot->description= "Exit tweaking mode for the action referenced by the active strip";
00229     
00230     /* api callbacks */
00231     ot->exec= nlaedit_disable_tweakmode_exec;
00232     ot->poll= nlaop_poll_tweakmode_on;
00233     
00234     /* flags */
00235     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00236 }
00237 
00238 /* *********************************************** */
00239 /* NLA Strips Range Stuff */
00240 
00241 /* *************************** Calculate Range ************************** */
00242 
00243 /* Get the min/max strip extents */
00244 static void get_nlastrip_extents (bAnimContext *ac, float *min, float *max, const short onlySel)
00245 {
00246     ListBase anim_data = {NULL, NULL};
00247     bAnimListElem *ale;
00248     int filter;
00249     
00250     /* get data to filter */
00251     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
00252     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00253     
00254     /* set large values to try to override */
00255     *min= 999999999.0f;
00256     *max= -999999999.0f;
00257     
00258     /* check if any channels to set range with */
00259     if (anim_data.first) {
00260         /* go through channels, finding max extents */
00261         for (ale= anim_data.first; ale; ale= ale->next) {
00262             NlaTrack *nlt = (NlaTrack *)ale->data;
00263             NlaStrip *strip;
00264             
00265             for (strip = nlt->strips.first; strip; strip = strip->next) {
00266                 /* only consider selected strips? */
00267                 if ((onlySel == 0) || (strip->flag & NLASTRIP_FLAG_SELECT)) {
00268                     /* extend range if appropriate */
00269                     *min = MIN2(*min, strip->start);
00270                     *max = MAX2(*max, strip->end);
00271                 }
00272             }
00273         }
00274         
00275         /* free memory */
00276         BLI_freelistN(&anim_data);
00277     }
00278     else {
00279         /* set default range */
00280         if (ac->scene) {
00281             *min= (float)ac->scene->r.sfra;
00282             *max= (float)ac->scene->r.efra;
00283         }
00284         else {
00285             *min= -5;
00286             *max= 100;
00287         }
00288     }
00289 }
00290 
00291 /* ****************** View-All Operator ****************** */
00292 
00293 static int nlaedit_viewall(bContext *C, const short onlySel)
00294 {
00295     bAnimContext ac;
00296     View2D *v2d;
00297     float extra;
00298     
00299     /* get editor data */
00300     if (ANIM_animdata_get_context(C, &ac) == 0)
00301         return OPERATOR_CANCELLED;
00302     v2d= &ac.ar->v2d;
00303     
00304     /* set the horizontal range, with an extra offset so that the extreme keys will be in view */
00305     get_nlastrip_extents(&ac, &v2d->cur.xmin, &v2d->cur.xmax, onlySel);
00306     
00307     extra= 0.1f * (v2d->cur.xmax - v2d->cur.xmin);
00308     v2d->cur.xmin -= extra;
00309     v2d->cur.xmax += extra;
00310     
00311     /* set vertical range */
00312     v2d->cur.ymax= 0.0f;
00313     v2d->cur.ymin= (float)-(v2d->mask.ymax - v2d->mask.ymin);
00314     
00315     /* do View2D syncing */
00316     UI_view2d_sync(CTX_wm_screen(C), CTX_wm_area(C), v2d, V2D_LOCK_COPY);
00317     
00318     /* just redraw this view */
00319     ED_area_tag_redraw(CTX_wm_area(C));
00320     
00321     return OPERATOR_FINISHED;
00322 }
00323 
00324 /* ......... */
00325 
00326 static int nlaedit_viewall_exec(bContext *C, wmOperator *UNUSED(op))
00327 {   
00328     /* whole range */
00329     return nlaedit_viewall(C, FALSE);
00330 }
00331 
00332 static int nlaedit_viewsel_exec(bContext *C, wmOperator *UNUSED(op))
00333 {
00334     /* only selected */
00335     return nlaedit_viewall(C, TRUE);
00336 }
00337  
00338 void NLA_OT_view_all (wmOperatorType *ot)
00339 {
00340     /* identifiers */
00341     ot->name= "View All";
00342     ot->idname= "NLA_OT_view_all";
00343     ot->description= "Reset viewable area to show full strips range";
00344     
00345     /* api callbacks */
00346     ot->exec= nlaedit_viewall_exec;
00347     ot->poll= ED_operator_nla_active;
00348     
00349     /* flags */
00350     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00351 }
00352 
00353 void NLA_OT_view_selected (wmOperatorType *ot)
00354 {
00355     /* identifiers */
00356     ot->name= "View Selected";
00357     ot->idname= "NLA_OT_view_selected";
00358     ot->description= "Reset viewable area to show selected strips range";
00359     
00360     /* api callbacks */
00361     ot->exec= nlaedit_viewsel_exec;
00362     ot->poll= ED_operator_nla_active;
00363     
00364     /* flags */
00365     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00366 }
00367 
00368 /* *********************************************** */
00369 /* NLA Editing Operations (Constructive/Destructive) */
00370 
00371 /* ******************** Add Action-Clip Operator ***************************** */
00372 /* Add a new Action-Clip strip to the active track (or the active block if no space in the track) */
00373 
00374 
00375 /* add the specified action as new strip */
00376 static int nlaedit_add_actionclip_exec (bContext *C, wmOperator *op)
00377 {
00378     bAnimContext ac;
00379     Scene *scene;
00380     
00381     ListBase anim_data = {NULL, NULL};
00382     bAnimListElem *ale;
00383     size_t items;
00384     int filter;
00385 
00386     bAction *act;
00387 
00388     float cfra;
00389     
00390     /* get editor data */
00391     if (ANIM_animdata_get_context(C, &ac) == 0)
00392         return OPERATOR_CANCELLED;
00393         
00394     scene= ac.scene;
00395     cfra= (float)CFRA;
00396         
00397     /* get action to use */
00398     act= BLI_findlink(&CTX_data_main(C)->action, RNA_enum_get(op->ptr, "action"));
00399     
00400     if (act == NULL) {
00401         BKE_report(op->reports, RPT_ERROR, "No valid Action to add");
00402         //printf("Add strip - actname = '%s' \n", actname);
00403         return OPERATOR_CANCELLED;
00404     }
00405     else if (act->idroot == 0) {
00406         /* hopefully in this case (i.e. library of userless actions), the user knows what they're doing... */
00407         BKE_reportf(op->reports, RPT_WARNING,
00408             "Action '%s' does not specify what datablocks it can be used on. Try setting the 'ID Root Type' setting from the Datablocks Editor for this Action to avoid future problems",
00409             act->id.name+2);
00410     }
00411     
00412     /* get a list of the editable tracks being shown in the NLA
00413      *  - this is limited to active ones for now, but could be expanded to 
00414      */
00415     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_ACTIVE | ANIMFILTER_FOREDIT);
00416     items= ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
00417     
00418     if (items == 0) {
00419         BKE_report(op->reports, RPT_ERROR, "No active track(s) to add strip to");
00420         return OPERATOR_CANCELLED;
00421     }
00422     
00423     /* for every active track, try to add strip to free space in track or to the top of the stack if no space */
00424     for (ale= anim_data.first; ale; ale= ale->next) {
00425         NlaTrack *nlt= (NlaTrack *)ale->data;
00426         AnimData *adt= ale->adt;
00427         NlaStrip *strip= NULL;
00428         
00429         /* sanity check: only apply actions of the right type for this ID 
00430          * NOTE: in the case that this hasn't been set, we've already warned the user about this already
00431          */
00432         if ((act->idroot) && (act->idroot != GS(ale->id->name))) {
00433             BKE_reportf(op->reports, RPT_ERROR, 
00434                 "Couldn't add action '%s' as it cannot be used relative to ID-blocks of type '%s'",
00435                 act->id.name+2, ale->id->name);
00436             continue;
00437         }
00438         
00439         /* create a new strip, and offset it to start on the current frame */
00440         strip= add_nlastrip(act);
00441         
00442         strip->end      += (cfra - strip->start);
00443         strip->start     = cfra;
00444         
00445         /* firstly try adding strip to our current track, but if that fails, add to a new track */
00446         if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
00447             /* trying to add to the current failed (no space), 
00448              * so add a new track to the stack, and add to that...
00449              */
00450             nlt= add_nlatrack(adt, NULL);
00451             BKE_nlatrack_add_strip(nlt, strip);
00452         }
00453         
00454         /* auto-name it */
00455         BKE_nlastrip_validate_name(adt, strip);
00456     }
00457     
00458     /* free temp data */
00459     BLI_freelistN(&anim_data);
00460     
00461     /* refresh auto strip properties */
00462     ED_nla_postop_refresh(&ac);
00463     
00464     /* set notifier that things have changed */
00465     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
00466     
00467     /* done */
00468     return OPERATOR_FINISHED;
00469 }
00470 
00471 void NLA_OT_actionclip_add (wmOperatorType *ot)
00472 {
00473     PropertyRNA *prop;
00474 
00475     /* identifiers */
00476     ot->name= "Add Action Strip";
00477     ot->idname= "NLA_OT_actionclip_add";
00478     ot->description= "Add an Action-Clip strip (i.e. an NLA Strip referencing an Action) to the active track";
00479     
00480     /* api callbacks */
00481     ot->invoke= WM_enum_search_invoke;
00482     ot->exec= nlaedit_add_actionclip_exec;
00483     ot->poll= nlaop_poll_tweakmode_off;
00484     
00485     /* flags */
00486     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00487     
00488     /* props */
00489         // TODO: this would be nicer as an ID-pointer...
00490     prop= RNA_def_enum(ot->srna, "action", DummyRNA_NULL_items, 0, "Action", "");
00491     RNA_def_enum_funcs(prop, RNA_action_itemf);
00492     ot->prop= prop;
00493 }
00494 
00495 /* ******************** Add Transition Operator ***************************** */
00496 /* Add a new transition strip between selected strips */
00497 
00498 static int nlaedit_add_transition_exec (bContext *C, wmOperator *op)
00499 {
00500     bAnimContext ac;
00501     
00502     ListBase anim_data = {NULL, NULL};
00503     bAnimListElem *ale;
00504     int filter;
00505     
00506     int done = 0;
00507     
00508     /* get editor data */
00509     if (ANIM_animdata_get_context(C, &ac) == 0)
00510         return OPERATOR_CANCELLED;
00511     
00512     /* get a list of the editable tracks being shown in the NLA */
00513     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
00514     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
00515     
00516     /* for each track, find pairs of strips to add transitions to */
00517     for (ale= anim_data.first; ale; ale= ale->next) {
00518         NlaTrack *nlt= (NlaTrack *)ale->data;
00519         AnimData *adt= ale->adt;
00520         NlaStrip *s1, *s2;
00521         
00522         /* get initial pair of strips */
00523         if ELEM(nlt->strips.first, NULL, nlt->strips.last)
00524             continue;
00525         s1= nlt->strips.first;
00526         s2= s1->next;
00527         
00528         /* loop over strips */
00529         for (; s1 && s2; s1=s2, s2=s2->next) {
00530             NlaStrip *strip;
00531             
00532             /* check if both are selected */
00533             if ELEM(0, (s1->flag & NLASTRIP_FLAG_SELECT), (s2->flag & NLASTRIP_FLAG_SELECT))
00534                 continue;
00535             /* check if there's space between the two */
00536             if (IS_EQF(s1->end, s2->start))
00537                 continue;
00538             /* make sure neither one is a transition 
00539              *  - although this is impossible to create with the standard tools, 
00540              *    the user may have altered the settings
00541              */
00542             if (ELEM(NLASTRIP_TYPE_TRANSITION, s1->type, s2->type))
00543                 continue;
00544             /* also make sure neither one is a soundclip */
00545             if (ELEM(NLASTRIP_TYPE_SOUND, s1->type, s2->type))
00546                 continue;
00547                 
00548             /* allocate new strip */
00549             strip= MEM_callocN(sizeof(NlaStrip), "NlaStrip");
00550             BLI_insertlinkafter(&nlt->strips, s1, strip);
00551             
00552             /* set the type */
00553             strip->type= NLASTRIP_TYPE_TRANSITION;
00554             
00555             /* generic settings 
00556              *  - selected flag to highlight this to the user
00557              *  - auto-blends to ensure that blend in/out values are automatically 
00558              *    determined by overlaps of strips
00559              */
00560             strip->flag = NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_AUTO_BLENDS;
00561             
00562             /* range is simply defined as the endpoints of the adjacent strips */
00563             strip->start    = s1->end;
00564             strip->end      = s2->start;
00565             
00566             /* scale and repeat aren't of any use, but shouldn't ever be 0 */
00567             strip->scale= 1.0f;
00568             strip->repeat = 1.0f;
00569             
00570             /* auto-name it */
00571             BKE_nlastrip_validate_name(adt, strip);
00572             
00573             /* make note of this */
00574             done++;
00575         }
00576     }
00577     
00578     /* free temp data */
00579     BLI_freelistN(&anim_data);
00580     
00581     /* was anything added? */
00582     if (done) {
00583         /* refresh auto strip properties */
00584         ED_nla_postop_refresh(&ac);
00585         
00586         /* set notifier that things have changed */
00587         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
00588         
00589         /* done */
00590         return OPERATOR_FINISHED;
00591     }
00592     else {
00593         BKE_report(op->reports, RPT_ERROR, "Needs at least a pair of adjacent selected strips with a gap between them");
00594         return OPERATOR_CANCELLED;
00595     }
00596 }
00597 
00598 void NLA_OT_transition_add (wmOperatorType *ot)
00599 {
00600     /* identifiers */
00601     ot->name= "Add Transition";
00602     ot->idname= "NLA_OT_transition_add";
00603     ot->description= "Add a transition strip between two adjacent selected strips";
00604     
00605     /* api callbacks */
00606     ot->exec= nlaedit_add_transition_exec;
00607     ot->poll= nlaop_poll_tweakmode_off;
00608     
00609     /* flags */
00610     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00611 }
00612 
00613 /* ******************** Add Sound Clip Operator ***************************** */
00614 /* Add a new sound clip */
00615 
00616 static int nlaedit_add_sound_exec (bContext *C, wmOperator *UNUSED(op))
00617 {
00618     bAnimContext ac;
00619     
00620     ListBase anim_data = {NULL, NULL};
00621     bAnimListElem *ale;
00622     int filter;
00623     
00624     Scene *scene;
00625     int cfra;
00626     
00627     /* get editor data */
00628     if (ANIM_animdata_get_context(C, &ac) == 0)
00629         return OPERATOR_CANCELLED;
00630     
00631     scene = ac.scene;
00632     cfra = CFRA;
00633     
00634     /* get a list of the editable tracks being shown in the NLA */
00635     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
00636     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
00637     
00638     /* for each track, add sound clips if it belongs to a speaker */
00639     // TODO: what happens if there aren't any tracks... well that's a more general problem for later
00640     for (ale= anim_data.first; ale; ale= ale->next) {
00641         Object *ob = (Object *)ale->id; /* may not be object until we actually check! */
00642         
00643         AnimData *adt = ale->adt;
00644         NlaTrack *nlt= (NlaTrack *)ale->data;
00645         NlaStrip *strip;
00646         
00647         /* does this belong to speaker - assumed to live on Object level only */
00648         if ((GS(ale->id->name) != ID_OB) || (ob->type != OB_SPEAKER))
00649             continue;
00650             
00651         /* create a new strip, and offset it to start on the current frame */
00652         strip= add_nla_soundstrip(ac.scene, ob->data); 
00653         
00654         strip->start    += cfra;
00655         strip->end      += cfra;
00656         
00657         /* firstly try adding strip to our current track, but if that fails, add to a new track */
00658         if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
00659             /* trying to add to the current failed (no space), 
00660              * so add a new track to the stack, and add to that...
00661              */
00662             nlt= add_nlatrack(adt, NULL);
00663             BKE_nlatrack_add_strip(nlt, strip);
00664         }
00665         
00666         /* auto-name it */
00667         BKE_nlastrip_validate_name(adt, strip);
00668     }
00669     
00670     /* free temp data */
00671     BLI_freelistN(&anim_data);
00672     
00673     /* refresh auto strip properties */
00674     ED_nla_postop_refresh(&ac);
00675     
00676     /* set notifier that things have changed */
00677     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
00678     
00679     /* done */
00680     return OPERATOR_FINISHED;
00681 }
00682 
00683 void NLA_OT_soundclip_add (wmOperatorType *ot)
00684 {
00685     /* identifiers */
00686     ot->name= "Add Sound Clip";
00687     ot->idname= "NLA_OT_soundclip_add";
00688     ot->description= "Add a strip for controlling when speaker plays its sound clip";
00689     
00690     /* api callbacks */
00691     ot->exec= nlaedit_add_sound_exec;
00692     ot->poll= nlaop_poll_tweakmode_off;
00693     
00694     /* flags */
00695     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00696 }
00697 
00698 /* ******************** Add Meta-Strip Operator ***************************** */
00699 /* Add new meta-strips incorporating the selected strips */
00700 
00701 /* add the specified action as new strip */
00702 static int nlaedit_add_meta_exec (bContext *C, wmOperator *UNUSED(op))
00703 {
00704     bAnimContext ac;
00705     
00706     ListBase anim_data = {NULL, NULL};
00707     bAnimListElem *ale;
00708     int filter;
00709     
00710     /* get editor data */
00711     if (ANIM_animdata_get_context(C, &ac) == 0)
00712         return OPERATOR_CANCELLED;
00713     
00714     /* get a list of the editable tracks being shown in the NLA */
00715     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
00716     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
00717     
00718     /* for each track, find pairs of strips to add transitions to */
00719     for (ale= anim_data.first; ale; ale= ale->next) {
00720         NlaTrack *nlt= (NlaTrack *)ale->data;
00721         AnimData *adt= ale->adt;
00722         NlaStrip *strip;
00723         
00724         /* create meta-strips from the continuous chains of selected strips */
00725         BKE_nlastrips_make_metas(&nlt->strips, 0);
00726         
00727         /* name the metas */
00728         for (strip= nlt->strips.first; strip; strip= strip->next) {
00729             /* auto-name this strip if selected (that means it is a meta) */
00730             if (strip->flag & NLASTRIP_FLAG_SELECT)
00731                 BKE_nlastrip_validate_name(adt, strip);
00732         }
00733     }
00734     
00735     /* free temp data */
00736     BLI_freelistN(&anim_data);
00737     
00738     /* set notifier that things have changed */
00739     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
00740     
00741     /* done */
00742     return OPERATOR_FINISHED;
00743 }
00744 
00745 void NLA_OT_meta_add (wmOperatorType *ot)
00746 {
00747     /* identifiers */
00748     ot->name= "Add Meta-Strips";
00749     ot->idname= "NLA_OT_meta_add";
00750     ot->description= "Add new meta-strips incorporating the selected strips";
00751     
00752     /* api callbacks */
00753     ot->exec= nlaedit_add_meta_exec;
00754     ot->poll= nlaop_poll_tweakmode_off;
00755     
00756     /* flags */
00757     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00758 }
00759 
00760 /* ******************** Remove Meta-Strip Operator ***************************** */
00761 /* Separate out the strips held by the selected meta-strips */
00762 
00763 static int nlaedit_remove_meta_exec (bContext *C, wmOperator *UNUSED(op))
00764 {
00765     bAnimContext ac;
00766     
00767     ListBase anim_data = {NULL, NULL};
00768     bAnimListElem *ale;
00769     int filter;
00770     
00771     /* get editor data */
00772     if (ANIM_animdata_get_context(C, &ac) == 0)
00773         return OPERATOR_CANCELLED;
00774     
00775     /* get a list of the editable tracks being shown in the NLA */
00776     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
00777     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
00778     
00779     /* for each track, find pairs of strips to add transitions to */
00780     for (ale= anim_data.first; ale; ale= ale->next) {
00781         NlaTrack *nlt= (NlaTrack *)ale->data;
00782         
00783         /* clear all selected meta-strips, regardless of whether they are temporary or not */
00784         BKE_nlastrips_clear_metas(&nlt->strips, 1, 0);
00785     }
00786     
00787     /* free temp data */
00788     BLI_freelistN(&anim_data);
00789     
00790     /* set notifier that things have changed */
00791     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
00792     
00793     /* done */
00794     return OPERATOR_FINISHED;
00795 }
00796 
00797 void NLA_OT_meta_remove (wmOperatorType *ot)
00798 {
00799     /* identifiers */
00800     ot->name= "Remove Meta-Strips";
00801     ot->idname= "NLA_OT_meta_remove";
00802     ot->description= "Separate out the strips held by the selected meta-strips";
00803     
00804     /* api callbacks */
00805     ot->exec= nlaedit_remove_meta_exec;
00806     ot->poll= nlaop_poll_tweakmode_off;
00807     
00808     /* flags */
00809     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00810 }
00811 
00812 /* ******************** Duplicate Strips Operator ************************** */
00813 /* Duplicates the selected NLA-Strips, putting them on new tracks above the one
00814  * the originals were housed in.
00815  */
00816  
00817 static int nlaedit_duplicate_exec (bContext *C, wmOperator *UNUSED(op))
00818 {
00819     bAnimContext ac;
00820     
00821     ListBase anim_data = {NULL, NULL};
00822     bAnimListElem *ale;
00823     int filter;
00824     
00825     short done = 0;
00826     
00827     /* get editor data */
00828     if (ANIM_animdata_get_context(C, &ac) == 0)
00829         return OPERATOR_CANCELLED;
00830         
00831     /* get a list of editable tracks being shown in the NLA */
00832     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
00833     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
00834     
00835     /* duplicate strips in tracks starting from the last one so that we're 
00836      * less likely to duplicate strips we just duplicated...
00837      */
00838     for (ale= anim_data.last; ale; ale= ale->prev) {
00839         NlaTrack *nlt= (NlaTrack *)ale->data;
00840         AnimData *adt= ale->adt;
00841         NlaStrip *strip, *nstrip, *next;
00842         NlaTrack *track;
00843         
00844         for (strip= nlt->strips.first; strip; strip= next) {
00845             next= strip->next;
00846             
00847             /* if selected, split the strip at its midpoint */
00848             if (strip->flag & NLASTRIP_FLAG_SELECT) {
00849                 /* make a copy (assume that this is possible) */
00850                 nstrip= copy_nlastrip(strip);
00851                 
00852                 /* in case there's no space in the track above, or we haven't got a reference to it yet, try adding */
00853                 if (BKE_nlatrack_add_strip(nlt->next, nstrip) == 0) {
00854                     /* need to add a new track above the one above the current one
00855                      *  - if the current one is the last one, nlt->next will be NULL, which defaults to adding 
00856                      *    at the top of the stack anyway...
00857                      */
00858                     track= add_nlatrack(adt, nlt->next);
00859                     BKE_nlatrack_add_strip(track, nstrip);
00860                 }
00861                 
00862                 /* deselect the original and the active flag */
00863                 strip->flag &= ~(NLASTRIP_FLAG_SELECT|NLASTRIP_FLAG_ACTIVE);
00864                 
00865                 /* auto-name newly created strip */
00866                 BKE_nlastrip_validate_name(adt, nstrip);
00867                 
00868                 done++;
00869             }
00870         }
00871     }
00872     
00873     /* free temp data */
00874     BLI_freelistN(&anim_data);
00875     
00876     if (done) {
00877         /* refresh auto strip properties */
00878         ED_nla_postop_refresh(&ac);
00879         
00880         /* set notifier that things have changed */
00881         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
00882         
00883         /* done */
00884         return OPERATOR_FINISHED;
00885     }
00886     else
00887         return OPERATOR_CANCELLED;
00888 }
00889 
00890 static int nlaedit_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
00891 {
00892     nlaedit_duplicate_exec(C, op);
00893     
00894     RNA_enum_set(op->ptr, "mode", TFM_TRANSLATION);
00895     WM_operator_name_call(C, "TRANSFORM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
00896 
00897     return OPERATOR_FINISHED;
00898 }
00899 
00900 void NLA_OT_duplicate (wmOperatorType *ot)
00901 {
00902     /* identifiers */
00903     ot->name= "Duplicate Strips";
00904     ot->idname= "NLA_OT_duplicate";
00905     ot->description= "Duplicate selected NLA-Strips, adding the new strips in new tracks above the originals";
00906     
00907     /* api callbacks */
00908     ot->invoke= nlaedit_duplicate_invoke;
00909     ot->exec= nlaedit_duplicate_exec;
00910     ot->poll= nlaop_poll_tweakmode_off;
00911     
00912     /* flags */
00913     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00914     
00915     /* to give to transform */
00916     RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", "");
00917 }
00918 
00919 /* ******************** Delete Strips Operator ***************************** */
00920 /* Deletes the selected NLA-Strips */
00921 
00922 static int nlaedit_delete_exec (bContext *C, wmOperator *UNUSED(op))
00923 {
00924     bAnimContext ac;
00925     
00926     ListBase anim_data = {NULL, NULL};
00927     bAnimListElem *ale;
00928     int filter;
00929     
00930     /* get editor data */
00931     if (ANIM_animdata_get_context(C, &ac) == 0)
00932         return OPERATOR_CANCELLED;
00933         
00934     /* get a list of the editable tracks being shown in the NLA */
00935     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
00936     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
00937     
00938     /* for each NLA-Track, delete all selected strips */
00939     for (ale= anim_data.first; ale; ale= ale->next) {
00940         NlaTrack *nlt= (NlaTrack *)ale->data;
00941         NlaStrip *strip, *nstrip;
00942         
00943         for (strip= nlt->strips.first; strip; strip= nstrip) {
00944             nstrip= strip->next;
00945             
00946             /* if selected, delete */
00947             if (strip->flag & NLASTRIP_FLAG_SELECT) {
00948                 /* if a strip either side of this was a transition, delete those too */
00949                 if ((strip->prev) && (strip->prev->type == NLASTRIP_TYPE_TRANSITION)) 
00950                     free_nlastrip(&nlt->strips, strip->prev);
00951                 if ((nstrip) && (nstrip->type == NLASTRIP_TYPE_TRANSITION)) {
00952                     nstrip= nstrip->next;
00953                     free_nlastrip(&nlt->strips, strip->next);
00954                 }
00955                 
00956                 /* finally, delete this strip */
00957                 free_nlastrip(&nlt->strips, strip);
00958             }
00959         }
00960     }
00961     
00962     /* free temp data */
00963     BLI_freelistN(&anim_data);
00964     
00965     /* refresh auto strip properties */
00966     ED_nla_postop_refresh(&ac);
00967     
00968     /* set notifier that things have changed */
00969     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
00970     
00971     /* done */
00972     return OPERATOR_FINISHED;
00973 }
00974 
00975 void NLA_OT_delete (wmOperatorType *ot)
00976 {
00977     /* identifiers */
00978     ot->name= "Delete Strips";
00979     ot->idname= "NLA_OT_delete";
00980     ot->description= "Delete selected strips";
00981     
00982     /* api callbacks */
00983     ot->exec= nlaedit_delete_exec;
00984     ot->poll= nlaop_poll_tweakmode_off;
00985     
00986     /* flags */
00987     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00988 }
00989 
00990 /* ******************** Split Strips Operator ***************************** */
00991 /* Splits the selected NLA-Strips into two strips at the midpoint of the strip */
00992 // TODO's? 
00993 //  - multiple splits
00994 //  - variable-length splits?
00995 
00996 /* split a given Action-Clip strip */
00997 static void nlaedit_split_strip_actclip (AnimData *adt, NlaTrack *nlt, NlaStrip *strip, float cfra)
00998 {
00999     NlaStrip *nstrip;
01000     float splitframe, splitaframe;
01001     
01002     /* calculate the frames to do the splitting at 
01003      *  - use current frame if within extents of strip 
01004      */
01005     if ((cfra > strip->start) && (cfra < strip->end)) {
01006         /* use the current frame */
01007         splitframe= cfra;
01008         splitaframe= nlastrip_get_frame(strip, cfra, NLATIME_CONVERT_UNMAP);
01009     }
01010     else {
01011         /* split in the middle */
01012         float len;
01013             
01014             /* strip extents */
01015         len= strip->end - strip->start;
01016         if (IS_EQF(len, 0.0f))
01017             return;
01018         else
01019             splitframe= strip->start + (len / 2.0f);
01020             
01021             /* action range */
01022         len= strip->actend - strip->actstart;
01023         if (IS_EQF(len, 0.0f))
01024             splitaframe= strip->actend;
01025         else
01026             splitaframe= strip->actstart + (len / 2.0f);
01027     }
01028     
01029     /* make a copy (assume that this is possible) and append
01030      * it immediately after the current strip
01031      */
01032     nstrip= copy_nlastrip(strip);
01033     BLI_insertlinkafter(&nlt->strips, strip, nstrip);
01034     
01035     /* set the endpoint of the first strip and the start of the new strip 
01036      * to the splitframe values calculated above
01037      */
01038     strip->end= splitframe;
01039     nstrip->start= splitframe;
01040     
01041     if ((splitaframe > strip->actstart) && (splitaframe < strip->actend)) {
01042         /* only do this if we're splitting down the middle...  */
01043         strip->actend= splitaframe;
01044         nstrip->actstart= splitaframe;
01045     }
01046     
01047     /* clear the active flag from the copy */
01048     nstrip->flag &= ~NLASTRIP_FLAG_ACTIVE;
01049     
01050     /* auto-name the new strip */
01051     BKE_nlastrip_validate_name(adt, nstrip);
01052 }
01053 
01054 /* split a given Meta strip */
01055 static void nlaedit_split_strip_meta (NlaTrack *nlt, NlaStrip *strip)
01056 {
01057     /* simply ungroup it for now...  */
01058     BKE_nlastrips_clear_metastrip(&nlt->strips, strip);
01059 }
01060 
01061 /* ----- */
01062 
01063 static int nlaedit_split_exec (bContext *C, wmOperator *UNUSED(op))
01064 {
01065     bAnimContext ac;
01066     
01067     ListBase anim_data = {NULL, NULL};
01068     bAnimListElem *ale;
01069     int filter;
01070     
01071     /* get editor data */
01072     if (ANIM_animdata_get_context(C, &ac) == 0)
01073         return OPERATOR_CANCELLED;
01074         
01075     /* get a list of editable tracks being shown in the NLA */
01076     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
01077     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
01078     
01079     /* for each NLA-Track, split all selected strips into two strips */
01080     for (ale= anim_data.first; ale; ale= ale->next) {
01081         NlaTrack *nlt= (NlaTrack *)ale->data;
01082         AnimData *adt= ale->adt;
01083         NlaStrip *strip, *next;
01084         
01085         for (strip= nlt->strips.first; strip; strip= next) {
01086             next= strip->next;
01087             
01088             /* if selected, split the strip at its midpoint */
01089             if (strip->flag & NLASTRIP_FLAG_SELECT) {
01090                 /* splitting method depends on the type of strip */
01091                 switch (strip->type) {
01092                     case NLASTRIP_TYPE_CLIP: /* action-clip */
01093                         nlaedit_split_strip_actclip(adt, nlt, strip, (float)ac.scene->r.cfra);
01094                         break;
01095                         
01096                     case NLASTRIP_TYPE_META: /* meta-strips need special handling */
01097                         nlaedit_split_strip_meta(nlt, strip);
01098                         break;
01099                     
01100                     default: /* for things like Transitions, do not split! */
01101                         break;
01102                 }
01103             }
01104         }
01105     }
01106     
01107     /* free temp data */
01108     BLI_freelistN(&anim_data);
01109     
01110     /* refresh auto strip properties */
01111     ED_nla_postop_refresh(&ac);
01112     
01113     /* set notifier that things have changed */
01114     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
01115     
01116     /* done */
01117     return OPERATOR_FINISHED;
01118 }
01119 
01120 void NLA_OT_split (wmOperatorType *ot)
01121 {
01122     /* identifiers */
01123     ot->name= "Split Strips";
01124     ot->idname= "NLA_OT_split";
01125     ot->description= "Split selected strips at their midpoints";
01126     
01127     /* api callbacks */
01128     ot->exec= nlaedit_split_exec;
01129     ot->poll= nlaop_poll_tweakmode_off;
01130     
01131     /* flags */
01132     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01133 }
01134 
01135 /* ******************** Bake Strips Operator ***************************** */
01136 /* Bakes the NLA Strips for the active AnimData blocks */
01137 
01138 static int nlaedit_bake_exec (bContext *C, wmOperator *UNUSED(op))
01139 {
01140     bAnimContext ac;
01141     
01142     ListBase anim_data = {NULL, NULL};
01143     bAnimListElem *ale;
01144     int filter;
01145 //  int flag = 0;
01146     
01147     /* get editor data */
01148     if (ANIM_animdata_get_context(C, &ac) == 0)
01149         return OPERATOR_CANCELLED;
01150         
01151     /* get a list of the editable tracks being shown in the NLA */
01152     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_FOREDIT);
01153     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
01154     
01155     /* for each AnimData block, bake strips to animdata... */
01156     for (ale= anim_data.first; ale; ale= ale->next) {
01157         //BKE_nla_bake(ac.scene, ale->id, ale->data, flag);
01158     }
01159     
01160     /* free temp data */
01161     BLI_freelistN(&anim_data);
01162     
01163     /* refresh auto strip properties */
01164     ED_nla_postop_refresh(&ac);
01165     
01166     /* set notifier that things have changed */
01167     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
01168     
01169     /* done */
01170     return OPERATOR_FINISHED;
01171 }
01172 
01173 void NLA_OT_bake (wmOperatorType *ot)
01174 {
01175     /* identifiers */
01176     ot->name= "Bake Strips";
01177     ot->idname= "NLA_OT_bake";
01178     ot->description= "Bake all strips of selected AnimData blocks";
01179     
01180     /* api callbacks */
01181     ot->exec= nlaedit_bake_exec;
01182     ot->poll= nlaop_poll_tweakmode_off;
01183     
01184     /* flags */
01185     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01186 }
01187 
01188 /* *********************************************** */
01189 /* NLA Editing Operations (Modifying) */
01190 
01191 /* ******************** Toggle Muting Operator ************************** */
01192 /* Toggles whether strips are muted or not */
01193 
01194 static int nlaedit_toggle_mute_exec (bContext *C, wmOperator *UNUSED(op))
01195 {
01196     bAnimContext ac;
01197     
01198     ListBase anim_data = {NULL, NULL};
01199     bAnimListElem *ale;
01200     int filter;
01201     
01202     /* get editor data */
01203     if (ANIM_animdata_get_context(C, &ac) == 0)
01204         return OPERATOR_CANCELLED;
01205         
01206     /* get a list of the editable tracks being shown in the NLA */
01207     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
01208     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
01209     
01210     /* go over all selected strips */
01211     for (ale= anim_data.first; ale; ale= ale->next) {
01212         NlaTrack *nlt= (NlaTrack *)ale->data;
01213         NlaStrip *strip;
01214         
01215         /* for every selected strip, toggle muting  */
01216         for (strip= nlt->strips.first; strip; strip= strip->next) {
01217             if (strip->flag & NLASTRIP_FLAG_SELECT) {
01218                 /* just flip the mute flag for now */
01219                 // TODO: have a pre-pass to check if mute all or unmute all?
01220                 strip->flag ^= NLASTRIP_FLAG_MUTED;
01221             }
01222         }
01223     }
01224     
01225     /* free temp data */
01226     BLI_freelistN(&anim_data);
01227     
01228     /* set notifier that things have changed */
01229     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
01230     
01231     /* done */
01232     return OPERATOR_FINISHED;
01233 }
01234 
01235 void NLA_OT_mute_toggle (wmOperatorType *ot)
01236 {
01237     /* identifiers */
01238     ot->name= "Toggle Muting";
01239     ot->idname= "NLA_OT_mute_toggle";
01240     ot->description= "Mute or un-mute selected strips";
01241     
01242     /* api callbacks */
01243     ot->exec= nlaedit_toggle_mute_exec;
01244     ot->poll= nlaop_poll_tweakmode_off;
01245     
01246     /* flags */
01247     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01248 }
01249 
01250 /* ******************** Swap Strips Operator ************************** */
01251 /* Tries to exchange strips within their owner tracks */
01252 
01253 static int nlaedit_swap_exec (bContext *C, wmOperator *op)
01254 {
01255     bAnimContext ac;
01256     
01257     ListBase anim_data = {NULL, NULL};
01258     bAnimListElem *ale;
01259     int filter;
01260     
01261     /* get editor data */
01262     if (ANIM_animdata_get_context(C, &ac) == 0)
01263         return OPERATOR_CANCELLED;
01264         
01265     /* get a list of the editable tracks being shown in the NLA */
01266     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
01267     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
01268     
01269     /* consider each track in turn */
01270     for (ale= anim_data.first; ale; ale= ale->next) {
01271         NlaTrack *nlt= (NlaTrack *)ale->data;
01272         
01273         NlaStrip *strip, *stripN=NULL;
01274         NlaStrip *sa=NULL, *sb=NULL;
01275         
01276         /* make temporary metastrips so that entire islands of selections can be moved around */
01277         BKE_nlastrips_make_metas(&nlt->strips, 1);
01278         
01279         /* special case: if there is only 1 island (i.e. temp meta BUT NOT unselected/normal/normal-meta strips) left after this, 
01280          * and this island has two strips inside it, then we should be able to just swap these still...
01281          */
01282         if ((nlt->strips.first == nlt->strips.last) && (nlt->strips.first != NULL)) {
01283             NlaStrip *mstrip = (NlaStrip *)nlt->strips.first;
01284             
01285             if ((mstrip->flag & NLASTRIP_FLAG_TEMP_META) && (BLI_countlist(&mstrip->strips) == 2)) 
01286             {
01287                 /* remove this temp meta, so that we can see the strips inside */
01288                 BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
01289             }
01290         }
01291         
01292         /* get two selected strips only (these will be metas due to prev step) to operate on
01293          *  - only allow swapping 2, as with more the context becomes unclear
01294          */
01295         for (strip = nlt->strips.first; strip; strip = stripN) {
01296             stripN = strip->next;
01297             
01298             if (strip->flag & NLASTRIP_FLAG_SELECT) {
01299                 /* first or second strip? */
01300                 if (sa == NULL) {
01301                     /* store as first */
01302                     sa = strip;
01303                 }
01304                 else if (sb == NULL) {
01305                     /* store as second */
01306                     sb = strip;
01307                 }
01308                 else {
01309                     /* too many selected */
01310                     break;
01311                 }
01312             }
01313         }
01314         
01315         if (strip) {
01316             /* too many selected warning */
01317             BKE_reportf(op->reports, RPT_WARNING, 
01318                 "Too many clusters of strips selected in NLA Track (%s): needs exactly 2 to be selected",
01319                 nlt->name);
01320         }
01321         else if (sa == NULL) {
01322             /* no warning as this is just a common case, and it may get annoying when doing multiple tracks */
01323         }
01324         else if (sb == NULL) {
01325             /* too few selected warning */
01326             BKE_reportf(op->reports, RPT_WARNING,
01327                 "Too few clusters of strips selected in NLA Track (%s): needs exactly 2 to be selected",
01328                 nlt->name);
01329         }
01330         else {
01331             float nsa[2], nsb[2];
01332             
01333             /* remove these strips from the track, so that we can test if they can fit in the proposed places */
01334             BLI_remlink(&nlt->strips, sa);
01335             BLI_remlink(&nlt->strips, sb);
01336             
01337             /* calculate new extents for strips */
01338                 /* a --> b */
01339             nsa[0] = sb->start;
01340             nsa[1] = sb->start + (sa->end - sa->start);
01341                 /* b --> a */
01342             nsb[0] = sa->start;
01343             nsb[1] = sa->start + (sb->end - sb->start);
01344             
01345             /* check if the track has room for the strips to be swapped */
01346             if (BKE_nlastrips_has_space(&nlt->strips, nsa[0], nsa[1]) && 
01347                 BKE_nlastrips_has_space(&nlt->strips, nsb[0], nsb[1]))
01348             {
01349                 /* set new extents for strips then */
01350                 sa->start = nsa[0];
01351                 sa->end   = nsa[1];
01352                 BKE_nlameta_flush_transforms(sa);
01353                 
01354                 sb->start = nsb[0];
01355                 sb->end   = nsb[1];
01356                 BKE_nlameta_flush_transforms(sb);
01357             }
01358             else {
01359                 /* not enough room to swap, so show message */
01360                 if ((sa->flag & NLASTRIP_FLAG_TEMP_META) || (sb->flag & NLASTRIP_FLAG_TEMP_META)) {
01361                     BKE_report(op->reports, RPT_WARNING,
01362                         "Cannot swap selected strips as they will not be able to fit in their new places");
01363                 }
01364                 else {
01365                     BKE_reportf(op->reports, RPT_WARNING,   
01366                         "Cannot swap '%s' and '%s' as one or both will not be able to fit in their new places",
01367                         sa->name, sb->name);
01368                 }
01369             }
01370             
01371             /* add strips back to track now */
01372             BKE_nlatrack_add_strip(nlt, sa);
01373             BKE_nlatrack_add_strip(nlt, sb);
01374         }
01375         
01376         /* clear (temp) metastrips */
01377         BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
01378     }
01379     
01380     /* free temp data */
01381     BLI_freelistN(&anim_data);
01382     
01383     /* refresh auto strip properties */
01384     ED_nla_postop_refresh(&ac);
01385     
01386     /* set notifier that things have changed */
01387     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
01388     
01389     /* done */
01390     return OPERATOR_FINISHED;
01391 }
01392 
01393 void NLA_OT_swap (wmOperatorType *ot)
01394 {
01395     /* identifiers */
01396     ot->name= "Swap Strips";
01397     ot->idname= "NLA_OT_swap";
01398     ot->description= "Swap order of selected strips within tracks";
01399     
01400     /* api callbacks */
01401     ot->exec= nlaedit_swap_exec;
01402     ot->poll= nlaop_poll_tweakmode_off;
01403     
01404     /* flags */
01405     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01406 }
01407 
01408 /* ******************** Move Strips Up Operator ************************** */
01409 /* Tries to move the selected strips into the track above if possible. */
01410 
01411 static int nlaedit_move_up_exec (bContext *C, wmOperator *UNUSED(op))
01412 {
01413     bAnimContext ac;
01414     
01415     ListBase anim_data = {NULL, NULL};
01416     bAnimListElem *ale;
01417     int filter;
01418     
01419     /* get editor data */
01420     if (ANIM_animdata_get_context(C, &ac) == 0)
01421         return OPERATOR_CANCELLED;
01422         
01423     /* get a list of the editable tracks being shown in the NLA */
01424     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
01425     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
01426     
01427     /* since we're potentially moving strips from lower tracks to higher tracks, we should
01428      * loop over the tracks in reverse order to avoid moving earlier strips up multiple tracks
01429      */
01430     for (ale= anim_data.last; ale; ale= ale->prev) {
01431         NlaTrack *nlt= (NlaTrack *)ale->data;
01432         NlaTrack *nltn= nlt->next;
01433         NlaStrip *strip, *stripn;
01434         
01435         /* if this track has no tracks after it, skip for now... */
01436         if (nltn == NULL)
01437             continue;
01438         
01439         /* for every selected strip, try to move */
01440         for (strip= nlt->strips.first; strip; strip= stripn) {
01441             stripn= strip->next;
01442             
01443             if (strip->flag & NLASTRIP_FLAG_SELECT) {
01444                 /* check if the track above has room for this strip */
01445                 if (BKE_nlatrack_has_space(nltn, strip->start, strip->end)) {
01446                     /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
01447                     BLI_remlink(&nlt->strips, strip);
01448                     BKE_nlatrack_add_strip(nltn, strip);
01449                 }
01450             }
01451         }
01452     }
01453     
01454     /* free temp data */
01455     BLI_freelistN(&anim_data);
01456     
01457     /* refresh auto strip properties */
01458     ED_nla_postop_refresh(&ac);
01459     
01460     /* set notifier that things have changed */
01461     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
01462     
01463     /* done */
01464     return OPERATOR_FINISHED;
01465 }
01466 
01467 void NLA_OT_move_up (wmOperatorType *ot)
01468 {
01469     /* identifiers */
01470     ot->name= "Move Strips Up";
01471     ot->idname= "NLA_OT_move_up";
01472     ot->description= "Move selected strips up a track if there's room";
01473     
01474     /* api callbacks */
01475     ot->exec= nlaedit_move_up_exec;
01476     ot->poll= nlaop_poll_tweakmode_off;
01477     
01478     /* flags */
01479     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01480 }
01481 
01482 /* ******************** Move Strips Down Operator ************************** */
01483 /* Tries to move the selected strips into the track above if possible. */
01484 
01485 static int nlaedit_move_down_exec (bContext *C, wmOperator *UNUSED(op))
01486 {
01487     bAnimContext ac;
01488     
01489     ListBase anim_data = {NULL, NULL};
01490     bAnimListElem *ale;
01491     int filter;
01492     
01493     /* get editor data */
01494     if (ANIM_animdata_get_context(C, &ac) == 0)
01495         return OPERATOR_CANCELLED;
01496         
01497     /* get a list of the editable tracks being shown in the NLA */
01498     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
01499     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
01500     
01501     /* loop through the tracks in normal order, since we're pushing strips down,
01502      * strips won't get operated on twice
01503      */
01504     for (ale= anim_data.first; ale; ale= ale->next) {
01505         NlaTrack *nlt= (NlaTrack *)ale->data;
01506         NlaTrack *nltp= nlt->prev;
01507         NlaStrip *strip, *stripn;
01508         
01509         /* if this track has no tracks before it, skip for now... */
01510         if (nltp == NULL)
01511             continue;
01512         
01513         /* for every selected strip, try to move */
01514         for (strip= nlt->strips.first; strip; strip= stripn) {
01515             stripn= strip->next;
01516             
01517             if (strip->flag & NLASTRIP_FLAG_SELECT) {
01518                 /* check if the track below has room for this strip */
01519                 if (BKE_nlatrack_has_space(nltp, strip->start, strip->end)) {
01520                     /* remove from its current track, and add to the one above (it 'should' work, so no need to worry) */
01521                     BLI_remlink(&nlt->strips, strip);
01522                     BKE_nlatrack_add_strip(nltp, strip);
01523                 }
01524             }
01525         }
01526     }
01527     
01528     /* free temp data */
01529     BLI_freelistN(&anim_data);
01530     
01531     /* refresh auto strip properties */
01532     ED_nla_postop_refresh(&ac);
01533     
01534     /* set notifier that things have changed */
01535     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
01536     
01537     /* done */
01538     return OPERATOR_FINISHED;
01539 }
01540 
01541 void NLA_OT_move_down (wmOperatorType *ot)
01542 {
01543     /* identifiers */
01544     ot->name= "Move Strips Down";
01545     ot->idname= "NLA_OT_move_down";
01546     ot->description= "Move selected strips down a track if there's room";
01547     
01548     /* api callbacks */
01549     ot->exec= nlaedit_move_down_exec;
01550     ot->poll= nlaop_poll_tweakmode_off;
01551     
01552     /* flags */
01553     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01554 }
01555 
01556 /* ******************** Sync Action Length Operator ***************************** */
01557 /* Recalculate the extents of the action ranges used for the selected strips  */
01558 
01559 static int nlaedit_sync_actlen_exec (bContext *C, wmOperator *op)
01560 {
01561     bAnimContext ac;
01562     
01563     ListBase anim_data = {NULL, NULL};
01564     bAnimListElem *ale;
01565     int filter;
01566     short active_only= RNA_boolean_get(op->ptr, "active");
01567     
01568     /* get editor data */
01569     if (ANIM_animdata_get_context(C, &ac) == 0)
01570         return OPERATOR_CANCELLED;
01571         
01572     /* get a list of the editable tracks being shown in the NLA */
01573     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
01574     if (active_only) filter |= ANIMFILTER_ACTIVE;
01575     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
01576     
01577     /* for each NLA-Track, apply scale of all selected strips */
01578     for (ale= anim_data.first; ale; ale= ale->next) {
01579         NlaTrack *nlt= (NlaTrack *)ale->data;
01580         NlaStrip *strip;
01581         
01582         for (strip= nlt->strips.first; strip; strip= strip->next) {
01583             /* strip selection/active status check */
01584             if (active_only) {
01585                 if ((strip->flag & NLASTRIP_FLAG_ACTIVE) == 0)
01586                     continue;
01587             }
01588             else {
01589                 if ((strip->flag & NLASTRIP_FLAG_SELECT) == 0)
01590                     continue;
01591             }
01592             
01593             /* must be action-clip only (transitions don't have scale) */
01594             if (strip->type == NLASTRIP_TYPE_CLIP) {
01595                 if (strip->act == NULL) 
01596                     continue;
01597                     
01598                 /* recalculate the length of the action */
01599                 calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
01600                 
01601                 /* adjust the strip extents in response to this */
01602                 BKE_nlastrip_recalculate_bounds(strip);
01603             }
01604         }
01605     }
01606     
01607     /* free temp data */
01608     BLI_freelistN(&anim_data);
01609     
01610     /* set notifier that things have changed */
01611     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
01612     
01613     /* done */
01614     return OPERATOR_FINISHED;
01615 }
01616 
01617 void NLA_OT_action_sync_length (wmOperatorType *ot)
01618 {
01619     /* identifiers */
01620     ot->name= "Sync Action Length";
01621     ot->idname= "NLA_OT_action_sync_length";
01622     ot->description= "Synchronise the length of the referenced Action with the length used in the strip";
01623     
01624     /* api callbacks */
01625     ot->exec= nlaedit_sync_actlen_exec;
01626     ot->poll= ED_operator_nla_active; // XXX: is this satisfactory... probably requires a check for active strip...
01627     
01628     /* flags */
01629     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01630     
01631     /* properties */
01632     ot->prop= RNA_def_boolean(ot->srna, "active", 1, "Active Strip Only", "Only sync the active length for the active strip");
01633 }
01634 
01635 /* ******************** Apply Scale Operator ***************************** */
01636 /* Reset the scaling of the selected strips to 1.0f */
01637 
01638 /* apply scaling to keyframe */
01639 static short bezt_apply_nlamapping (KeyframeEditData *ked, BezTriple *bezt)
01640 {
01641     /* NLA-strip which has this scaling is stored in ked->data */
01642     NlaStrip *strip= (NlaStrip *)ked->data;
01643     
01644     /* adjust all the times */
01645     bezt->vec[0][0]= nlastrip_get_frame(strip, bezt->vec[0][0], NLATIME_CONVERT_MAP);
01646     bezt->vec[1][0]= nlastrip_get_frame(strip, bezt->vec[1][0], NLATIME_CONVERT_MAP);
01647     bezt->vec[2][0]= nlastrip_get_frame(strip, bezt->vec[2][0], NLATIME_CONVERT_MAP);
01648     
01649     /* nothing to return or else we exit */
01650     return 0;
01651 }
01652 
01653 static int nlaedit_apply_scale_exec (bContext *C, wmOperator *UNUSED(op))
01654 {
01655     bAnimContext ac;
01656     
01657     ListBase anim_data = {NULL, NULL};
01658     bAnimListElem *ale;
01659     int filter;
01660     
01661     KeyframeEditData ked= {{NULL}};
01662     
01663     /* get editor data */
01664     if (ANIM_animdata_get_context(C, &ac) == 0)
01665         return OPERATOR_CANCELLED;
01666         
01667     /* get a list of the editable tracks being shown in the NLA */
01668     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
01669     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
01670     
01671     /* init the editing data */
01672     
01673     /* for each NLA-Track, apply scale of all selected strips */
01674     for (ale= anim_data.first; ale; ale= ale->next) {
01675         NlaTrack *nlt= (NlaTrack *)ale->data;
01676         NlaStrip *strip;
01677         
01678         for (strip= nlt->strips.first; strip; strip= strip->next) {
01679             /* strip must be selected, and must be action-clip only (transitions don't have scale) */
01680             if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
01681                 /* if the referenced action is used by other strips, make this strip use its own copy */
01682                 if (strip->act == NULL) 
01683                     continue;
01684                 if (strip->act->id.us > 1) {
01685                     /* make a copy of the Action to work on */
01686                     bAction *act= copy_action(strip->act);
01687                     
01688                     /* set this as the new referenced action, decrementing the users of the old one */
01689                     strip->act->id.us--;
01690                     strip->act= act;
01691                 }
01692                 
01693                 /* setup iterator, and iterate over all the keyframes in the action, applying this scaling */
01694                 ked.data= strip;
01695                 ANIM_animchanneldata_keyframes_loop(&ked, ac.ads, strip->act, ALE_ACT, NULL, bezt_apply_nlamapping, calchandles_fcurve);
01696                 
01697                 /* clear scale of strip now that it has been applied,
01698                  * and recalculate the extents of the action now that it has been scaled
01699                  * but leave everything else alone 
01700                  */
01701                 strip->scale= 1.0f;
01702                 calc_action_range(strip->act, &strip->actstart, &strip->actend, 0);
01703             }
01704         }
01705     }
01706     
01707     /* free temp data */
01708     BLI_freelistN(&anim_data);
01709     
01710     /* set notifier that things have changed */
01711     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
01712     
01713     /* done */
01714     return OPERATOR_FINISHED;
01715 }
01716 
01717 void NLA_OT_apply_scale (wmOperatorType *ot)
01718 {
01719     /* identifiers */
01720     ot->name= "Apply Scale";
01721     ot->idname= "NLA_OT_apply_scale";
01722     ot->description= "Apply scaling of selected strips to their referenced Actions";
01723     
01724     /* api callbacks */
01725     ot->exec= nlaedit_apply_scale_exec;
01726     ot->poll= nlaop_poll_tweakmode_off;
01727     
01728     /* flags */
01729     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01730 }
01731 
01732 /* ******************** Clear Scale Operator ***************************** */
01733 /* Reset the scaling of the selected strips to 1.0f */
01734 
01735 static int nlaedit_clear_scale_exec (bContext *C, wmOperator *UNUSED(op))
01736 {
01737     bAnimContext ac;
01738     
01739     ListBase anim_data = {NULL, NULL};
01740     bAnimListElem *ale;
01741     int filter;
01742     
01743     /* get editor data */
01744     if (ANIM_animdata_get_context(C, &ac) == 0)
01745         return OPERATOR_CANCELLED;
01746         
01747     /* get a list of the editable tracks being shown in the NLA */
01748     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
01749     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
01750     
01751     /* for each NLA-Track, reset scale of all selected strips */
01752     for (ale= anim_data.first; ale; ale= ale->next) {
01753         NlaTrack *nlt= (NlaTrack *)ale->data;
01754         NlaStrip *strip;
01755         
01756         for (strip= nlt->strips.first; strip; strip= strip->next) {
01757             /* strip must be selected, and must be action-clip only (transitions don't have scale) */
01758             if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
01759                 PointerRNA strip_ptr;
01760                 
01761                 RNA_pointer_create(NULL, &RNA_NlaStrip, strip, &strip_ptr);
01762                 RNA_float_set(&strip_ptr, "scale", 1.0f);
01763             }
01764         }
01765     }
01766     
01767     /* free temp data */
01768     BLI_freelistN(&anim_data);
01769     
01770     /* refresh auto strip properties */
01771     ED_nla_postop_refresh(&ac);
01772     
01773     /* set notifier that things have changed */
01774     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
01775     
01776     /* done */
01777     return OPERATOR_FINISHED;
01778 }
01779 
01780 void NLA_OT_clear_scale (wmOperatorType *ot)
01781 {
01782     /* identifiers */
01783     ot->name= "Clear Scale";
01784     ot->idname= "NLA_OT_clear_scale";
01785     ot->description= "Reset scaling of selected strips";
01786     
01787     /* api callbacks */
01788     ot->exec= nlaedit_clear_scale_exec;
01789     ot->poll= nlaop_poll_tweakmode_off;
01790     
01791     /* flags */
01792     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01793 }
01794 
01795 /* ******************** Snap Strips Operator ************************** */
01796 /* Moves the start-point of the selected strips to the specified places */
01797 
01798 /* defines for snap keyframes tool */
01799 static EnumPropertyItem prop_nlaedit_snap_types[] = {
01800     {NLAEDIT_SNAP_CFRA, "CFRA", 0, "Current frame", ""},
01801     {NLAEDIT_SNAP_NEAREST_FRAME, "NEAREST_FRAME", 0, "Nearest Frame", ""}, // XXX as single entry?
01802     {NLAEDIT_SNAP_NEAREST_SECOND, "NEAREST_SECOND", 0, "Nearest Second", ""}, // XXX as single entry?
01803     {NLAEDIT_SNAP_NEAREST_MARKER, "NEAREST_MARKER", 0, "Nearest Marker", ""},
01804     {0, NULL, 0, NULL, NULL}
01805 };
01806 
01807 static int nlaedit_snap_exec (bContext *C, wmOperator *op)
01808 {
01809     bAnimContext ac;
01810     
01811     ListBase anim_data = {NULL, NULL};
01812     bAnimListElem *ale;
01813     int filter;
01814     
01815     Scene *scene;
01816     int mode = RNA_enum_get(op->ptr, "type");
01817     float secf;
01818     
01819     /* get editor data */
01820     if (ANIM_animdata_get_context(C, &ac) == 0)
01821         return OPERATOR_CANCELLED;
01822         
01823     /* get a list of the editable tracks being shown in the NLA */
01824     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
01825     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
01826     
01827     /* get some necessary vars */
01828     scene= ac.scene;
01829     secf= (float)FPS;
01830     
01831     /* since we may add tracks, perform this in reverse order */
01832     for (ale= anim_data.last; ale; ale= ale->prev) {
01833         ListBase tmp_strips = {NULL, NULL};
01834         AnimData *adt= ale->adt;
01835         NlaTrack *nlt= (NlaTrack *)ale->data;
01836         NlaStrip *strip, *stripn;
01837         NlaTrack *track;
01838         
01839         /* create meta-strips from the continuous chains of selected strips */
01840         BKE_nlastrips_make_metas(&nlt->strips, 1);
01841         
01842         /* apply the snapping to all the temp meta-strips, then put them in a separate list to be added
01843          * back to the original only if they still fit
01844          */
01845         for (strip= nlt->strips.first; strip; strip= stripn) {
01846             stripn= strip->next;
01847             
01848             if (strip->flag & NLASTRIP_FLAG_TEMP_META) {
01849                 float start, end;
01850                 
01851                 /* get the existing end-points */
01852                 start= strip->start;
01853                 end= strip->end;
01854                 
01855                 /* calculate new start position based on snapping mode */
01856                 switch (mode) {
01857                     case NLAEDIT_SNAP_CFRA: /* to current frame */
01858                         strip->start= (float)CFRA;
01859                         break;
01860                     case NLAEDIT_SNAP_NEAREST_FRAME: /* to nearest frame */
01861                         strip->start= floorf(start+0.5f);
01862                         break;
01863                     case NLAEDIT_SNAP_NEAREST_SECOND: /* to nearest second */
01864                         strip->start= floorf(start/secf + 0.5f) * secf;
01865                         break;
01866                     case NLAEDIT_SNAP_NEAREST_MARKER: /* to nearest marker */
01867                         strip->start= (float)ED_markers_find_nearest_marker_time(ac.markers, start);
01868                         break;
01869                     default: /* just in case... no snapping */
01870                         strip->start= start;
01871                         break;
01872                 }
01873                 
01874                 /* get new endpoint based on start-point (and old length) */
01875                 strip->end= strip->start + (end - start);
01876                 
01877                 /* apply transforms to meta-strip to its children */
01878                 BKE_nlameta_flush_transforms(strip);
01879                 
01880                 /* remove strip from track, and add to the temp buffer */
01881                 BLI_remlink(&nlt->strips, strip);
01882                 BLI_addtail(&tmp_strips, strip);
01883             }
01884         }
01885         
01886         /* try adding each meta-strip back to the track one at a time, to make sure they'll fit */
01887         for (strip= tmp_strips.first; strip; strip= stripn) {
01888             stripn= strip->next;
01889             
01890             /* remove from temp-strips list */
01891             BLI_remlink(&tmp_strips, strip);
01892             
01893             /* in case there's no space in the current track, try adding */
01894             if (BKE_nlatrack_add_strip(nlt, strip) == 0) {
01895                 /* need to add a new track above the current one */
01896                 track= add_nlatrack(adt, nlt);
01897                 BKE_nlatrack_add_strip(track, strip);
01898                 
01899                 /* clear temp meta-strips on this new track, as we may not be able to get back to it */
01900                 BKE_nlastrips_clear_metas(&track->strips, 0, 1);
01901             }
01902         }
01903         
01904         /* remove the meta-strips now that we're done */
01905         BKE_nlastrips_clear_metas(&nlt->strips, 0, 1);
01906     }
01907     
01908     /* free temp data */
01909     BLI_freelistN(&anim_data);
01910     
01911     /* refresh auto strip properties */
01912     ED_nla_postop_refresh(&ac);
01913     
01914     /* set notifier that things have changed */
01915     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
01916     
01917     /* done */
01918     return OPERATOR_FINISHED;
01919 }
01920 
01921 void NLA_OT_snap (wmOperatorType *ot)
01922 {
01923     /* identifiers */
01924     ot->name= "Snap Strips";
01925     ot->idname= "NLA_OT_snap";
01926     ot->description= "Move start of strips to specified time";
01927     
01928     /* api callbacks */
01929     ot->invoke= WM_menu_invoke;
01930     ot->exec= nlaedit_snap_exec;
01931     ot->poll= nlaop_poll_tweakmode_off;
01932     
01933     /* flags */
01934     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01935     
01936     /* properties */
01937     ot->prop= RNA_def_enum(ot->srna, "type", prop_nlaedit_snap_types, 0, "Type", "");
01938 }
01939 
01940 /* *********************************************** */
01941 /* NLA Modifiers */
01942 
01943 /* ******************** Add F-Modifier Operator *********************** */
01944 
01945 /* present a special customised popup menu for this, with some filtering */
01946 static int nla_fmodifier_add_invoke (bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
01947 {
01948     uiPopupMenu *pup;
01949     uiLayout *layout;
01950     int i;
01951     
01952     pup= uiPupMenuBegin(C, "Add F-Modifier", ICON_NONE);
01953     layout= uiPupMenuLayout(pup);
01954     
01955     /* start from 1 to skip the 'Invalid' modifier type */
01956     for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
01957         FModifierTypeInfo *fmi= get_fmodifier_typeinfo(i);
01958         
01959         /* check if modifier is valid for this context */
01960         if (fmi == NULL)
01961             continue;
01962         if (i == FMODIFIER_TYPE_CYCLES) /* we already have repeat... */
01963             continue;
01964         
01965         /* add entry to add this type of modifier */
01966         uiItemEnumO(layout, "NLA_OT_fmodifier_add", fmi->name, 0, "type", i);
01967     }
01968     uiItemS(layout);
01969     
01970     uiPupMenuEnd(C, pup);
01971     
01972     return OPERATOR_CANCELLED;
01973 }
01974 
01975 static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
01976 {
01977     bAnimContext ac;
01978     
01979     ListBase anim_data = {NULL, NULL};
01980     bAnimListElem *ale;
01981     int filter;
01982     
01983     FModifier *fcm;
01984     int type= RNA_enum_get(op->ptr, "type");
01985     short onlyActive = RNA_boolean_get(op->ptr, "only_active");
01986     
01987     /* get editor data */
01988     if (ANIM_animdata_get_context(C, &ac) == 0)
01989         return OPERATOR_CANCELLED;
01990         
01991     /* get a list of the editable tracks being shown in the NLA */
01992     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
01993     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
01994     
01995     /* for each NLA-Track, add the specified modifier to all selected strips */
01996     for (ale= anim_data.first; ale; ale= ale->next) {
01997         NlaTrack *nlt= (NlaTrack *)ale->data;
01998         NlaStrip *strip;
01999         
02000         for (strip= nlt->strips.first; strip; strip=strip->next) {
02001             /* can F-Modifier be added to the current strip? */
02002             if (onlyActive) {
02003                 /* if not active, cannot add since we're only adding to active strip */
02004                 if ((strip->flag & NLASTRIP_FLAG_ACTIVE)==0)
02005                     continue;
02006             }
02007             else {
02008                 /* strip must be selected, since we're not just doing active */
02009                 if ((strip->flag & NLASTRIP_FLAG_SELECT)==0)
02010                     continue;
02011             }
02012             
02013             /* sound clips are not affected by FModifiers */
02014             if (strip->type == NLASTRIP_TYPE_SOUND)
02015                 continue;
02016             
02017             /* add F-Modifier of specified type to selected, and make it the active one */
02018             fcm= add_fmodifier(&strip->modifiers, type);
02019             
02020             if (fcm)
02021                 set_active_fmodifier(&strip->modifiers, fcm);
02022             else {
02023                 BKE_reportf(op->reports, RPT_ERROR,
02024                     "Modifier couldn't be added to (%s : %s) (see console for details)",
02025                     nlt->name, strip->name);
02026             }
02027         }
02028     }
02029     
02030     /* free temp data */
02031     BLI_freelistN(&anim_data);
02032     
02033     /* set notifier that things have changed */
02034     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
02035     
02036     /* done */
02037     return OPERATOR_FINISHED;
02038 }
02039  
02040 void NLA_OT_fmodifier_add (wmOperatorType *ot)
02041 {
02042     /* identifiers */
02043     ot->name= "Add F-Modifier";
02044     ot->idname= "NLA_OT_fmodifier_add";
02045     ot->description= "Add a F-Modifier of the specified type to the selected NLA-Strips";
02046     
02047     /* api callbacks */
02048     ot->invoke= nla_fmodifier_add_invoke;
02049     ot->exec= nla_fmodifier_add_exec;
02050     ot->poll= nlaop_poll_tweakmode_off; 
02051     
02052     /* flags */
02053     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02054     
02055     /* id-props */
02056     ot->prop= RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", "");
02057     RNA_def_boolean(ot->srna, "only_active", 0, "Only Active", "Only add a F-Modifier of the specified type to the active strip");
02058 }
02059 
02060 /* ******************** Copy F-Modifiers Operator *********************** */
02061 
02062 static int nla_fmodifier_copy_exec(bContext *C, wmOperator *op)
02063 {
02064     bAnimContext ac;
02065     ListBase anim_data = {NULL, NULL};
02066     bAnimListElem *ale;
02067     int filter, ok=0;
02068     
02069     /* get editor data */
02070     if (ANIM_animdata_get_context(C, &ac) == 0)
02071         return OPERATOR_CANCELLED;
02072     
02073     /* clear buffer first */
02074     free_fmodifiers_copybuf();
02075     
02076     /* get a list of the editable tracks being shown in the NLA */
02077     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT);
02078     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
02079     
02080     /* for each NLA-Track, add the specified modifier to all selected strips */
02081     for (ale= anim_data.first; ale; ale= ale->next) {
02082         NlaTrack *nlt= (NlaTrack *)ale->data;
02083         NlaStrip *strip;
02084         
02085         for (strip= nlt->strips.first; strip; strip=strip->next) {
02086             /* only add F-Modifier if on active strip? */
02087             if ((strip->flag & NLASTRIP_FLAG_ACTIVE)==0)
02088                 continue;
02089                 
02090             // TODO: when 'active' vs 'all' boolean is added, change last param!
02091             ok += ANIM_fmodifiers_copy_to_buf(&strip->modifiers, 0);
02092         }
02093     }
02094     
02095     /* successful or not? */
02096     if (ok == 0) {
02097         BKE_report(op->reports, RPT_ERROR, "No F-Modifiers available to be copied");
02098         return OPERATOR_CANCELLED;
02099     }
02100     else
02101         return OPERATOR_FINISHED;
02102 }
02103  
02104 void NLA_OT_fmodifier_copy (wmOperatorType *ot)
02105 {
02106     /* identifiers */
02107     ot->name= "Copy F-Modifiers";
02108     ot->idname= "NLA_OT_fmodifier_copy";
02109     ot->description= "Copy the F-Modifier(s) of the active NLA-Strip";
02110     
02111     /* api callbacks */
02112     ot->exec= nla_fmodifier_copy_exec;
02113     ot->poll= nlaop_poll_tweakmode_off; 
02114     
02115     /* flags */
02116     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02117     
02118     /* id-props */
02119     //ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All F-Modifiers", "Copy all the F-Modifiers, instead of just the active one");
02120 }
02121 
02122 /* ******************** Paste F-Modifiers Operator *********************** */
02123 
02124 static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
02125 {
02126     bAnimContext ac;
02127     ListBase anim_data = {NULL, NULL};
02128     bAnimListElem *ale;
02129     int filter, ok=0;
02130     
02131     /* get editor data */
02132     if (ANIM_animdata_get_context(C, &ac) == 0)
02133         return OPERATOR_CANCELLED;
02134     
02135     /* get a list of the editable tracks being shown in the NLA */
02136     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT);
02137     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
02138     
02139     /* for each NLA-Track, add the specified modifier to all selected strips */
02140     for (ale= anim_data.first; ale; ale= ale->next) {
02141         NlaTrack *nlt= (NlaTrack *)ale->data;
02142         NlaStrip *strip;
02143         
02144         for (strip= nlt->strips.first; strip; strip=strip->next) {
02145             // TODO: do we want to replace existing modifiers? add user pref for that!
02146             ok += ANIM_fmodifiers_paste_from_buf(&strip->modifiers, 0);
02147         }
02148     }
02149     
02150     /* clean up */
02151     BLI_freelistN(&anim_data);
02152     
02153     /* successful or not? */
02154     if (ok) {
02155         /* set notifier that things have changed */
02156         /* set notifier that things have changed */
02157         WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL);
02158         return OPERATOR_FINISHED;
02159     }
02160     else {
02161         BKE_report(op->reports, RPT_ERROR, "No F-Modifiers to paste");
02162         return OPERATOR_CANCELLED;
02163     }
02164 }
02165  
02166 void NLA_OT_fmodifier_paste (wmOperatorType *ot)
02167 {
02168     /* identifiers */
02169     ot->name= "Paste F-Modifiers";
02170     ot->idname= "NLA_OT_fmodifier_paste";
02171     ot->description= "Add copied F-Modifiers to the selected NLA-Strips";
02172     
02173     /* api callbacks */
02174     ot->exec= nla_fmodifier_paste_exec;
02175     ot->poll= nlaop_poll_tweakmode_off;
02176     
02177     /* flags */
02178     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
02179 }
02180 
02181 /* *********************************************** */