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 <stdlib.h> 00035 #include <math.h> 00036 00037 #include "DNA_anim_types.h" 00038 #include "DNA_object_types.h" 00039 #include "DNA_scene_types.h" 00040 00041 #include "BLI_blenlib.h" 00042 #include "BLI_math.h" 00043 #include "BLI_rand.h" 00044 #include "BLI_utildefines.h" 00045 00046 #include "BKE_animsys.h" 00047 #include "BKE_nla.h" 00048 #include "BKE_context.h" 00049 #include "BKE_global.h" 00050 #include "BKE_screen.h" 00051 00052 #include "ED_anim_api.h" 00053 #include "ED_keyframes_edit.h" 00054 #include "ED_screen.h" 00055 00056 #include "RNA_access.h" 00057 #include "RNA_define.h" 00058 00059 #include "WM_api.h" 00060 #include "WM_types.h" 00061 00062 #include "UI_view2d.h" 00063 00064 #include "nla_intern.h" // own include 00065 00066 /* *********************************************** */ 00067 /* Operators for NLA channels-list which need to be different from the standard Animation Editor ones */ 00068 00069 /* ******************** Mouse-Click Operator *********************** */ 00070 /* Depending on the channel that was clicked on, the mouse click will activate whichever 00071 * part of the channel is relevant. 00072 * 00073 * NOTE: eventually, this should probably be phased out when many of these things are replaced with buttons 00074 * --> Most channels are now selection only... 00075 */ 00076 00077 static int mouse_nla_channels (bAnimContext *ac, float x, int channel_index, short selectmode) 00078 { 00079 ListBase anim_data = {NULL, NULL}; 00080 bAnimListElem *ale; 00081 int filter; 00082 00083 View2D *v2d= &ac->ar->v2d; 00084 int notifierFlags = 0; 00085 00086 /* get the channel that was clicked on */ 00087 /* filter channels */ 00088 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); 00089 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00090 00091 /* get channel from index */ 00092 ale= BLI_findlink(&anim_data, channel_index); 00093 if (ale == NULL) { 00094 /* channel not found */ 00095 if (G.f & G_DEBUG) 00096 printf("Error: animation channel (index = %d) not found in mouse_anim_channels() \n", channel_index); 00097 00098 BLI_freelistN(&anim_data); 00099 return 0; 00100 } 00101 00102 /* action to take depends on what channel we've got */ 00103 // WARNING: must keep this in sync with the equivalent function in anim_channels_edit.c 00104 switch (ale->type) { 00105 case ANIMTYPE_SCENE: 00106 { 00107 Scene *sce= (Scene *)ale->data; 00108 AnimData *adt= sce->adt; 00109 00110 /* set selection status */ 00111 if (selectmode == SELECT_INVERT) { 00112 /* swap select */ 00113 sce->flag ^= SCE_DS_SELECTED; 00114 if (adt) adt->flag ^= ADT_UI_SELECTED; 00115 } 00116 else { 00117 sce->flag |= SCE_DS_SELECTED; 00118 if (adt) adt->flag |= ADT_UI_SELECTED; 00119 } 00120 00121 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED); 00122 } 00123 break; 00124 case ANIMTYPE_OBJECT: 00125 { 00126 bDopeSheet *ads= (bDopeSheet *)ac->data; 00127 Scene *sce= (Scene *)ads->source; 00128 Base *base= (Base *)ale->data; 00129 Object *ob= base->object; 00130 AnimData *adt= ob->adt; 00131 00132 if (nlaedit_is_tweakmode_on(ac) == 0) { 00133 /* set selection status */ 00134 if (selectmode == SELECT_INVERT) { 00135 /* swap select */ 00136 base->flag ^= SELECT; 00137 ob->flag= base->flag; 00138 00139 if (adt) adt->flag ^= ADT_UI_SELECTED; 00140 } 00141 else { 00142 Base *b; 00143 00144 /* deselect all */ 00145 // TODO: should this deselect all other types of channels too? 00146 for (b= sce->base.first; b; b= b->next) { 00147 b->flag &= ~SELECT; 00148 b->object->flag= b->flag; 00149 if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED|ADT_UI_ACTIVE); 00150 } 00151 00152 /* select object now */ 00153 base->flag |= SELECT; 00154 ob->flag |= SELECT; 00155 if (adt) adt->flag |= ADT_UI_SELECTED; 00156 } 00157 00158 if ((adt) && (adt->flag & ADT_UI_SELECTED)) 00159 adt->flag |= ADT_UI_ACTIVE; 00160 00161 /* notifiers - channel was selected */ 00162 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED); 00163 } 00164 } 00165 break; 00166 00167 case ANIMTYPE_FILLACTD: /* Action Expander */ 00168 case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ 00169 case ANIMTYPE_DSLAM: 00170 case ANIMTYPE_DSCAM: 00171 case ANIMTYPE_DSCUR: 00172 case ANIMTYPE_DSSKEY: 00173 case ANIMTYPE_DSWOR: 00174 case ANIMTYPE_DSNTREE: 00175 case ANIMTYPE_DSPART: 00176 case ANIMTYPE_DSMBALL: 00177 case ANIMTYPE_DSARM: 00178 case ANIMTYPE_DSMESH: 00179 case ANIMTYPE_DSTEX: 00180 case ANIMTYPE_DSLAT: 00181 case ANIMTYPE_DSSPK: 00182 { 00183 /* sanity checking... */ 00184 if (ale->adt) { 00185 /* select/deselect */ 00186 if (selectmode == SELECT_INVERT) { 00187 /* inverse selection status of this AnimData block only */ 00188 ale->adt->flag ^= ADT_UI_SELECTED; 00189 } 00190 else { 00191 /* select AnimData block by itself */ 00192 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); 00193 ale->adt->flag |= ADT_UI_SELECTED; 00194 } 00195 00196 /* set active? */ 00197 if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) 00198 ale->adt->flag |= ADT_UI_ACTIVE; 00199 } 00200 00201 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED); 00202 } 00203 break; 00204 00205 case ANIMTYPE_NLATRACK: 00206 { 00207 NlaTrack *nlt= (NlaTrack *)ale->data; 00208 AnimData *adt= ale->adt; 00209 short offset; 00210 00211 /* offset for start of channel (on LHS of channel-list) */ 00212 if (ale->id) { 00213 /* special exception for materials and particles */ 00214 if (ELEM(GS(ale->id->name),ID_MA,ID_PA)) 00215 offset= 21 + NLACHANNEL_BUTTON_WIDTH; 00216 else 00217 offset= 14; 00218 } 00219 else 00220 offset= 0; 00221 00222 if (x >= (v2d->cur.xmax-NLACHANNEL_BUTTON_WIDTH)) { 00223 /* toggle protection (only if there's a toggle there) */ 00224 nlt->flag ^= NLATRACK_PROTECTED; 00225 00226 /* notifier flags - channel was edited */ 00227 notifierFlags |= (ND_ANIMCHAN|NA_EDITED); 00228 } 00229 else if (x >= (v2d->cur.xmax-2*NLACHANNEL_BUTTON_WIDTH)) { 00230 /* toggle mute */ 00231 nlt->flag ^= NLATRACK_MUTED; 00232 00233 /* notifier flags - channel was edited */ 00234 notifierFlags |= (ND_ANIMCHAN|NA_EDITED); 00235 } 00236 else if (x <= ((NLACHANNEL_BUTTON_WIDTH*2)+offset)) { 00237 /* toggle 'solo' */ 00238 BKE_nlatrack_solo_toggle(adt, nlt); 00239 00240 /* notifier flags - channel was edited */ 00241 notifierFlags |= (ND_ANIMCHAN|NA_EDITED); 00242 } 00243 else if (nlaedit_is_tweakmode_on(ac) == 0) { 00244 /* set selection */ 00245 if (selectmode == SELECT_INVERT) { 00246 /* inverse selection status of this F-Curve only */ 00247 nlt->flag ^= NLATRACK_SELECTED; 00248 } 00249 else { 00250 /* select F-Curve by itself */ 00251 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); 00252 nlt->flag |= NLATRACK_SELECTED; 00253 } 00254 00255 /* if NLA-Track is selected now, make NLA-Track the 'active' one in the visible list */ 00256 if (nlt->flag & NLATRACK_SELECTED) 00257 ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK); 00258 00259 /* notifier flags - channel was selected */ 00260 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED); 00261 } 00262 } 00263 break; 00264 case ANIMTYPE_NLAACTION: 00265 { 00266 AnimData *adt= BKE_animdata_from_id(ale->id); 00267 00268 if (x >= (v2d->cur.xmax-NLACHANNEL_BUTTON_WIDTH)) { 00269 if (nlaedit_is_tweakmode_on(ac) == 0) { 00270 /* 'push-down' action - only usable when not in TweakMode */ 00271 // TODO: make this use the operator instead of calling the function directly 00272 // however, calling the operator requires that we supply the args, and that works with proper buttons only 00273 BKE_nla_action_pushdown(adt); 00274 } 00275 else { 00276 /* when in tweakmode, this button becomes the toggle for mapped editing */ 00277 adt->flag ^= ADT_NLA_EDIT_NOMAP; 00278 } 00279 00280 /* changes to NLA-Action occurred */ 00281 notifierFlags |= ND_NLA_ACTCHANGE; 00282 } 00283 } 00284 break; 00285 00286 default: 00287 if (G.f & G_DEBUG) 00288 printf("Error: Invalid channel type in mouse_nla_channels() \n"); 00289 } 00290 00291 /* free channels */ 00292 BLI_freelistN(&anim_data); 00293 00294 /* return the notifier-flags set */ 00295 return notifierFlags; 00296 } 00297 00298 /* ------------------- */ 00299 00300 /* handle clicking */ 00301 static int nlachannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event) 00302 { 00303 bAnimContext ac; 00304 SpaceNla *snla; 00305 ARegion *ar; 00306 View2D *v2d; 00307 int channel_index; 00308 int notifierFlags = 0; 00309 short selectmode; 00310 float x, y; 00311 00312 /* get editor data */ 00313 if (ANIM_animdata_get_context(C, &ac) == 0) 00314 return OPERATOR_CANCELLED; 00315 00316 /* get useful pointers from animation context data */ 00317 snla= (SpaceNla *)ac.sl; 00318 ar= ac.ar; 00319 v2d= &ar->v2d; 00320 00321 /* select mode is either replace (deselect all, then add) or add/extend */ 00322 if (RNA_boolean_get(op->ptr, "extend")) 00323 selectmode= SELECT_INVERT; 00324 else 00325 selectmode= SELECT_REPLACE; 00326 00327 /* figure out which channel user clicked in 00328 * Note: although channels technically start at y= NLACHANNEL_FIRST, we need to adjust by half a channel's height 00329 * so that the tops of channels get caught ok. Since NLACHANNEL_FIRST is really NLACHANNEL_HEIGHT, we simply use 00330 * NLACHANNEL_HEIGHT_HALF. 00331 */ 00332 UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y); 00333 UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index); 00334 00335 /* handle mouse-click in the relevant channel then */ 00336 notifierFlags= mouse_nla_channels(&ac, x, channel_index, selectmode); 00337 00338 /* set notifier that things have changed */ 00339 WM_event_add_notifier(C, NC_ANIMATION|notifierFlags, NULL); 00340 00341 return OPERATOR_FINISHED; 00342 } 00343 00344 void NLA_OT_channels_click (wmOperatorType *ot) 00345 { 00346 /* identifiers */ 00347 ot->name= "Mouse Click on NLA Channels"; 00348 ot->idname= "NLA_OT_channels_click"; 00349 ot->description= "Handle clicks to select NLA channels"; 00350 00351 /* api callbacks */ 00352 ot->invoke= nlachannels_mouseclick_invoke; 00353 ot->poll= ED_operator_nla_active; 00354 00355 /* flags */ 00356 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00357 00358 /* id-props */ 00359 RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY 00360 } 00361 00362 /* *********************************************** */ 00363 /* Special Operators */ 00364 00365 /* ******************** Add Tracks Operator ***************************** */ 00366 /* Add NLA Tracks to the same AnimData block as a selected track, or above the selected tracks */ 00367 00368 static int nlaedit_add_tracks_exec (bContext *C, wmOperator *op) 00369 { 00370 bAnimContext ac; 00371 00372 ListBase anim_data = {NULL, NULL}; 00373 bAnimListElem *ale; 00374 int filter; 00375 00376 AnimData *lastAdt = NULL; 00377 short above_sel= RNA_boolean_get(op->ptr, "above_selected"); 00378 00379 /* get editor data */ 00380 if (ANIM_animdata_get_context(C, &ac) == 0) 00381 return OPERATOR_CANCELLED; 00382 00383 /* get a list of the AnimData blocks being shown in the NLA */ 00384 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL); 00385 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 00386 00387 /* add tracks... */ 00388 for (ale= anim_data.first; ale; ale= ale->next) { 00389 if (ale->type == ANIMTYPE_NLATRACK) { 00390 NlaTrack *nlt= (NlaTrack *)ale->data; 00391 AnimData *adt= ale->adt; 00392 00393 /* check if just adding a new track above this one, 00394 * or whether we're adding a new one to the top of the stack that this one belongs to 00395 */ 00396 if (above_sel) { 00397 /* just add a new one above this one */ 00398 add_nlatrack(adt, nlt); 00399 } 00400 else if ((lastAdt == NULL) || (adt != lastAdt)) { 00401 /* add one track to the top of the owning AnimData's stack, then don't add anymore to this stack */ 00402 add_nlatrack(adt, NULL); 00403 lastAdt= adt; 00404 } 00405 } 00406 } 00407 00408 /* free temp data */ 00409 BLI_freelistN(&anim_data); 00410 00411 /* set notifier that things have changed */ 00412 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL); 00413 00414 /* done */ 00415 return OPERATOR_FINISHED; 00416 } 00417 00418 void NLA_OT_tracks_add (wmOperatorType *ot) 00419 { 00420 /* identifiers */ 00421 ot->name= "Add Track(s)"; 00422 ot->idname= "NLA_OT_tracks_add"; 00423 ot->description= "Add NLA-Tracks above/after the selected tracks"; 00424 00425 /* api callbacks */ 00426 ot->exec= nlaedit_add_tracks_exec; 00427 ot->poll= nlaop_poll_tweakmode_off; 00428 00429 /* flags */ 00430 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00431 00432 /* properties */ 00433 RNA_def_boolean(ot->srna, "above_selected", 0, "Above Selected", "Add a new NLA Track above every existing selected one"); 00434 } 00435 00436 /* ******************** Delete Tracks Operator ***************************** */ 00437 /* Delete selected NLA Tracks */ 00438 00439 static int nlaedit_delete_tracks_exec (bContext *C, wmOperator *UNUSED(op)) 00440 { 00441 bAnimContext ac; 00442 00443 ListBase anim_data = {NULL, NULL}; 00444 bAnimListElem *ale; 00445 int filter; 00446 00447 /* get editor data */ 00448 if (ANIM_animdata_get_context(C, &ac) == 0) 00449 return OPERATOR_CANCELLED; 00450 00451 /* get a list of the AnimData blocks being shown in the NLA */ 00452 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL); 00453 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 00454 00455 /* delete tracks */ 00456 for (ale= anim_data.first; ale; ale= ale->next) { 00457 if(ale->type == ANIMTYPE_NLATRACK) { 00458 NlaTrack *nlt= (NlaTrack *)ale->data; 00459 AnimData *adt= ale->adt; 00460 00461 /* if track is currently 'solo', then AnimData should have its 00462 * 'has solo' flag disabled 00463 */ 00464 if (nlt->flag & NLATRACK_SOLO) 00465 adt->flag &= ~ADT_NLA_SOLO_TRACK; 00466 00467 /* call delete on this track - deletes all strips too */ 00468 free_nlatrack(&adt->nla_tracks, nlt); 00469 } 00470 } 00471 00472 /* free temp data */ 00473 BLI_freelistN(&anim_data); 00474 00475 /* set notifier that things have changed */ 00476 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL); 00477 00478 /* done */ 00479 return OPERATOR_FINISHED; 00480 } 00481 00482 void NLA_OT_delete_tracks (wmOperatorType *ot) 00483 { 00484 /* identifiers */ 00485 ot->name= "Delete Tracks"; 00486 ot->idname= "NLA_OT_delete_tracks"; 00487 ot->description= "Delete selected NLA-Tracks and the strips they contain"; 00488 00489 /* api callbacks */ 00490 ot->exec= nlaedit_delete_tracks_exec; 00491 ot->poll= nlaop_poll_tweakmode_off; 00492 00493 /* flags */ 00494 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00495 } 00496 00497 /* *********************************************** */