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