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