|
Blender
V2.59
|
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 /* *********************************************** */