|
Blender
V2.59
|
00001 /* 00002 * $Id: nla_channels.c 36790 2011-05-20 07:40:05Z campbellbarton $ 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 <stdlib.h> 00037 #include <math.h> 00038 00039 #include "DNA_anim_types.h" 00040 #include "DNA_object_types.h" 00041 #include "DNA_scene_types.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_animsys.h" 00049 #include "BKE_nla.h" 00050 #include "BKE_context.h" 00051 #include "BKE_global.h" 00052 #include "BKE_screen.h" 00053 00054 #include "ED_anim_api.h" 00055 #include "ED_keyframes_edit.h" 00056 #include "ED_screen.h" 00057 00058 #include "RNA_access.h" 00059 #include "RNA_define.h" 00060 00061 #include "WM_api.h" 00062 #include "WM_types.h" 00063 00064 #include "UI_view2d.h" 00065 00066 #include "nla_intern.h" // own include 00067 00068 /* *********************************************** */ 00069 /* Operators for NLA channels-list which need to be different from the standard Animation Editor ones */ 00070 00071 /* ******************** Mouse-Click Operator *********************** */ 00072 /* Depending on the channel that was clicked on, the mouse click will activate whichever 00073 * part of the channel is relevant. 00074 * 00075 * NOTE: eventually, this should probably be phased out when many of these things are replaced with buttons 00076 * --> Most channels are now selection only... 00077 */ 00078 00079 static int mouse_nla_channels (bAnimContext *ac, float x, int channel_index, short selectmode) 00080 { 00081 ListBase anim_data = {NULL, NULL}; 00082 bAnimListElem *ale; 00083 int filter; 00084 View2D *v2d= &ac->ar->v2d; 00085 int notifierFlags = 0; 00086 00087 /* get the channel that was clicked on */ 00088 /* filter channels */ 00089 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS); 00090 filter= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00091 00092 /* get channel from index */ 00093 ale= BLI_findlink(&anim_data, channel_index); 00094 if (ale == NULL) { 00095 /* channel not found */ 00096 if (G.f & G_DEBUG) 00097 printf("Error: animation channel (index = %d) not found in mouse_anim_channels() \n", channel_index); 00098 00099 BLI_freelistN(&anim_data); 00100 return 0; 00101 } 00102 00103 /* action to take depends on what channel we've got */ 00104 // WARNING: must keep this in sync with the equivalent function in anim_channels_edit.c 00105 switch (ale->type) { 00106 case ANIMTYPE_SCENE: 00107 { 00108 Scene *sce= (Scene *)ale->data; 00109 AnimData *adt= sce->adt; 00110 00111 /* set selection status */ 00112 if (selectmode == SELECT_INVERT) { 00113 /* swap select */ 00114 sce->flag ^= SCE_DS_SELECTED; 00115 if (adt) adt->flag ^= ADT_UI_SELECTED; 00116 } 00117 else { 00118 sce->flag |= SCE_DS_SELECTED; 00119 if (adt) adt->flag |= ADT_UI_SELECTED; 00120 } 00121 00122 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED); 00123 } 00124 break; 00125 case ANIMTYPE_OBJECT: 00126 { 00127 bDopeSheet *ads= (bDopeSheet *)ac->data; 00128 Scene *sce= (Scene *)ads->source; 00129 Base *base= (Base *)ale->data; 00130 Object *ob= base->object; 00131 AnimData *adt= ob->adt; 00132 00133 if (nlaedit_is_tweakmode_on(ac) == 0) { 00134 /* set selection status */ 00135 if (selectmode == SELECT_INVERT) { 00136 /* swap select */ 00137 base->flag ^= SELECT; 00138 ob->flag= base->flag; 00139 00140 if (adt) adt->flag ^= ADT_UI_SELECTED; 00141 } 00142 else { 00143 Base *b; 00144 00145 /* deselect all */ 00146 // TODO: should this deselect all other types of channels too? 00147 for (b= sce->base.first; b; b= b->next) { 00148 b->flag &= ~SELECT; 00149 b->object->flag= b->flag; 00150 if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED|ADT_UI_ACTIVE); 00151 } 00152 00153 /* select object now */ 00154 base->flag |= SELECT; 00155 ob->flag |= SELECT; 00156 if (adt) adt->flag |= ADT_UI_SELECTED; 00157 } 00158 00159 if ((adt) && (adt->flag & ADT_UI_SELECTED)) 00160 adt->flag |= ADT_UI_ACTIVE; 00161 00162 /* notifiers - channel was selected */ 00163 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED); 00164 } 00165 } 00166 break; 00167 00168 case ANIMTYPE_FILLACTD: /* Action Expander */ 00169 case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ 00170 case ANIMTYPE_DSLAM: 00171 case ANIMTYPE_DSCAM: 00172 case ANIMTYPE_DSCUR: 00173 case ANIMTYPE_DSSKEY: 00174 case ANIMTYPE_DSWOR: 00175 case ANIMTYPE_DSNTREE: 00176 case ANIMTYPE_DSPART: 00177 case ANIMTYPE_DSMBALL: 00178 case ANIMTYPE_DSARM: 00179 case ANIMTYPE_DSMESH: 00180 case ANIMTYPE_DSTEX: 00181 case ANIMTYPE_DSLAT: 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 ARegion *ar; 00305 View2D *v2d; 00306 int channel_index; 00307 int notifierFlags = 0; 00308 short selectmode; 00309 float x, y; 00310 00311 /* get editor data */ 00312 if (ANIM_animdata_get_context(C, &ac) == 0) 00313 return OPERATOR_CANCELLED; 00314 00315 /* get useful pointers from animation context data */ 00316 ar= ac.ar; 00317 v2d= &ar->v2d; 00318 00319 /* select mode is either replace (deselect all, then add) or add/extend */ 00320 if (RNA_boolean_get(op->ptr, "extend")) 00321 selectmode= SELECT_INVERT; 00322 else 00323 selectmode= SELECT_REPLACE; 00324 00325 /* figure out which channel user clicked in 00326 * Note: although channels technically start at y= NLACHANNEL_FIRST, we need to adjust by half a channel's height 00327 * so that the tops of channels get caught ok. Since NLACHANNEL_FIRST is really NLACHANNEL_HEIGHT, we simply use 00328 * NLACHANNEL_HEIGHT_HALF. 00329 */ 00330 UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y); 00331 UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP, 0, (float)NLACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index); 00332 00333 /* handle mouse-click in the relevant channel then */ 00334 notifierFlags= mouse_nla_channels(&ac, x, channel_index, selectmode); 00335 00336 /* set notifier that things have changed */ 00337 WM_event_add_notifier(C, NC_ANIMATION|notifierFlags, NULL); 00338 00339 return OPERATOR_FINISHED; 00340 } 00341 00342 void NLA_OT_channels_click (wmOperatorType *ot) 00343 { 00344 /* identifiers */ 00345 ot->name= "Mouse Click on NLA Channels"; 00346 ot->idname= "NLA_OT_channels_click"; 00347 ot->description= "Handle clicks to select NLA channels"; 00348 00349 /* api callbacks */ 00350 ot->invoke= nlachannels_mouseclick_invoke; 00351 ot->poll= ED_operator_nla_active; 00352 00353 /* flags */ 00354 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00355 00356 /* id-props */ 00357 RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY 00358 } 00359 00360 /* *********************************************** */ 00361 /* Special Operators */ 00362 00363 /* ******************** Add Tracks Operator ***************************** */ 00364 /* Add NLA Tracks to the same AnimData block as a selected track, or above the selected tracks */ 00365 00366 static int nlaedit_add_tracks_exec (bContext *C, wmOperator *op) 00367 { 00368 bAnimContext ac; 00369 00370 ListBase anim_data = {NULL, NULL}; 00371 bAnimListElem *ale; 00372 int filter; 00373 00374 AnimData *lastAdt = NULL; 00375 short above_sel= RNA_boolean_get(op->ptr, "above_selected"); 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 AnimData blocks being shown in the NLA */ 00382 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_SEL); 00383 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 00384 00385 /* add tracks... */ 00386 for (ale= anim_data.first; ale; ale= ale->next) { 00387 if(ale->type == ANIMTYPE_NLATRACK) { 00388 NlaTrack *nlt= (NlaTrack *)ale->data; 00389 AnimData *adt= ale->adt; 00390 00391 /* check if just adding a new track above this one, 00392 * or whether we're adding a new one to the top of the stack that this one belongs to 00393 */ 00394 if (above_sel) { 00395 /* just add a new one above this one */ 00396 add_nlatrack(adt, nlt); 00397 } 00398 else if ((lastAdt == NULL) || (adt != lastAdt)) { 00399 /* add one track to the top of the owning AnimData's stack, then don't add anymore to this stack */ 00400 add_nlatrack(adt, NULL); 00401 lastAdt= adt; 00402 } 00403 } 00404 } 00405 00406 /* free temp data */ 00407 BLI_freelistN(&anim_data); 00408 00409 /* set notifier that things have changed */ 00410 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL); 00411 00412 /* done */ 00413 return OPERATOR_FINISHED; 00414 } 00415 00416 void NLA_OT_tracks_add (wmOperatorType *ot) 00417 { 00418 /* identifiers */ 00419 ot->name= "Add Track(s)"; 00420 ot->idname= "NLA_OT_tracks_add"; 00421 ot->description= "Add NLA-Tracks above/after the selected tracks"; 00422 00423 /* api callbacks */ 00424 ot->exec= nlaedit_add_tracks_exec; 00425 ot->poll= nlaop_poll_tweakmode_off; 00426 00427 /* flags */ 00428 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00429 00430 /* properties */ 00431 RNA_def_boolean(ot->srna, "above_selected", 0, "Above Selected", "Add a new NLA Track above every existing selected one."); 00432 } 00433 00434 /* ******************** Delete Tracks Operator ***************************** */ 00435 /* Delete selected NLA Tracks */ 00436 00437 static int nlaedit_delete_tracks_exec (bContext *C, wmOperator *UNUSED(op)) 00438 { 00439 bAnimContext ac; 00440 00441 ListBase anim_data = {NULL, NULL}; 00442 bAnimListElem *ale; 00443 int filter; 00444 00445 /* get editor data */ 00446 if (ANIM_animdata_get_context(C, &ac) == 0) 00447 return OPERATOR_CANCELLED; 00448 00449 /* get a list of the AnimData blocks being shown in the NLA */ 00450 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NLATRACKS | ANIMFILTER_SEL); 00451 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 00452 00453 /* delete tracks */ 00454 for (ale= anim_data.first; ale; ale= ale->next) { 00455 if(ale->type == ANIMTYPE_NLATRACK) { 00456 NlaTrack *nlt= (NlaTrack *)ale->data; 00457 AnimData *adt= ale->adt; 00458 00459 /* if track is currently 'solo', then AnimData should have its 00460 * 'has solo' flag disabled 00461 */ 00462 if (nlt->flag & NLATRACK_SOLO) 00463 adt->flag &= ~ADT_NLA_SOLO_TRACK; 00464 00465 /* call delete on this track - deletes all strips too */ 00466 free_nlatrack(&adt->nla_tracks, nlt); 00467 } 00468 } 00469 00470 /* free temp data */ 00471 BLI_freelistN(&anim_data); 00472 00473 /* set notifier that things have changed */ 00474 WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_EDITED, NULL); 00475 00476 /* done */ 00477 return OPERATOR_FINISHED; 00478 } 00479 00480 void NLA_OT_delete_tracks (wmOperatorType *ot) 00481 { 00482 /* identifiers */ 00483 ot->name= "Delete Tracks"; 00484 ot->idname= "NLA_OT_delete_tracks"; 00485 ot->description= "Delete selected NLA-Tracks and the strips they contain"; 00486 00487 /* api callbacks */ 00488 ot->exec= nlaedit_delete_tracks_exec; 00489 ot->poll= nlaop_poll_tweakmode_off; 00490 00491 /* flags */ 00492 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00493 } 00494 00495 /* *********************************************** */