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 * Contributor(s): Joshua Leung 00022 * 00023 * ***** END GPL LICENSE BLOCK ***** 00024 */ 00025 00031 #include <stdio.h> 00032 #include <stdlib.h> 00033 #include <string.h> 00034 00035 #include "MEM_guardedalloc.h" 00036 00037 #include "BLI_blenlib.h" 00038 #include "BLI_utildefines.h" 00039 #include "BKE_library.h" 00040 00041 #include "DNA_anim_types.h" 00042 #include "DNA_object_types.h" 00043 #include "DNA_scene_types.h" 00044 #include "DNA_key_types.h" 00045 #include "DNA_gpencil_types.h" 00046 00047 #include "RNA_access.h" 00048 #include "RNA_define.h" 00049 00050 #include "BKE_action.h" 00051 #include "BKE_fcurve.h" 00052 #include "BKE_gpencil.h" 00053 #include "BKE_context.h" 00054 #include "BKE_global.h" 00055 00056 #include "UI_view2d.h" 00057 00058 #include "ED_anim_api.h" 00059 #include "ED_keyframes_edit.h" // XXX move the select modes out of there! 00060 #include "ED_screen.h" 00061 00062 #include "WM_api.h" 00063 #include "WM_types.h" 00064 00065 /* ************************************************************************** */ 00066 /* CHANNELS API - Exposed API */ 00067 00068 /* -------------------------- Selection ------------------------------------- */ 00069 00070 /* Set the given animation-channel as the active one for the active context */ 00071 // TODO: extend for animdata types... 00072 void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int filter, void *channel_data, short channel_type) 00073 { 00074 ListBase anim_data = {NULL, NULL}; 00075 bAnimListElem *ale; 00076 00077 /* try to build list of filtered items */ 00078 ANIM_animdata_filter(ac, &anim_data, filter, data, datatype); 00079 if (anim_data.first == NULL) 00080 return; 00081 00082 /* only clear the 'active' flag for the channels of the same type */ 00083 for (ale= anim_data.first; ale; ale= ale->next) { 00084 /* skip if types don't match */ 00085 if (channel_type != ale->type) 00086 continue; 00087 00088 /* flag to set depends on type */ 00089 switch (ale->type) { 00090 case ANIMTYPE_GROUP: 00091 { 00092 bActionGroup *agrp= (bActionGroup *)ale->data; 00093 00094 ACHANNEL_SET_FLAG(agrp, ACHANNEL_SETFLAG_CLEAR, AGRP_ACTIVE); 00095 } 00096 break; 00097 case ANIMTYPE_FCURVE: 00098 { 00099 FCurve *fcu= (FCurve *)ale->data; 00100 00101 ACHANNEL_SET_FLAG(fcu, ACHANNEL_SETFLAG_CLEAR, FCURVE_ACTIVE); 00102 } 00103 break; 00104 case ANIMTYPE_NLATRACK: 00105 { 00106 NlaTrack *nlt= (NlaTrack *)ale->data; 00107 00108 ACHANNEL_SET_FLAG(nlt, ACHANNEL_SETFLAG_CLEAR, NLATRACK_ACTIVE); 00109 } 00110 break; 00111 00112 case ANIMTYPE_FILLACTD: /* Action Expander */ 00113 case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ 00114 case ANIMTYPE_DSLAM: 00115 case ANIMTYPE_DSCAM: 00116 case ANIMTYPE_DSCUR: 00117 case ANIMTYPE_DSSKEY: 00118 case ANIMTYPE_DSWOR: 00119 case ANIMTYPE_DSPART: 00120 case ANIMTYPE_DSMBALL: 00121 case ANIMTYPE_DSARM: 00122 case ANIMTYPE_DSMESH: 00123 case ANIMTYPE_DSTEX: 00124 case ANIMTYPE_DSLAT: 00125 case ANIMTYPE_DSSPK: 00126 { 00127 /* need to verify that this data is valid for now */ 00128 if (ale->adt) { 00129 ACHANNEL_SET_FLAG(ale->adt, ACHANNEL_SETFLAG_CLEAR, ADT_UI_ACTIVE); 00130 } 00131 } 00132 break; 00133 } 00134 } 00135 00136 /* set active flag */ 00137 if (channel_data) { 00138 switch (channel_type) { 00139 case ANIMTYPE_GROUP: 00140 { 00141 bActionGroup *agrp= (bActionGroup *)channel_data; 00142 agrp->flag |= AGRP_ACTIVE; 00143 } 00144 break; 00145 case ANIMTYPE_FCURVE: 00146 { 00147 FCurve *fcu= (FCurve *)channel_data; 00148 fcu->flag |= FCURVE_ACTIVE; 00149 } 00150 break; 00151 case ANIMTYPE_NLATRACK: 00152 { 00153 NlaTrack *nlt= (NlaTrack *)channel_data; 00154 nlt->flag |= NLATRACK_ACTIVE; 00155 } 00156 break; 00157 00158 case ANIMTYPE_FILLACTD: /* Action Expander */ 00159 case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ 00160 case ANIMTYPE_DSLAM: 00161 case ANIMTYPE_DSCAM: 00162 case ANIMTYPE_DSCUR: 00163 case ANIMTYPE_DSSKEY: 00164 case ANIMTYPE_DSWOR: 00165 case ANIMTYPE_DSPART: 00166 case ANIMTYPE_DSMBALL: 00167 case ANIMTYPE_DSARM: 00168 case ANIMTYPE_DSMESH: 00169 case ANIMTYPE_DSLAT: 00170 case ANIMTYPE_DSSPK: 00171 { 00172 /* need to verify that this data is valid for now */ 00173 if (ale && ale->adt) { 00174 ale->adt->flag |= ADT_UI_ACTIVE; 00175 } 00176 } 00177 break; 00178 } 00179 } 00180 00181 /* clean up */ 00182 BLI_freelistN(&anim_data); 00183 } 00184 00185 /* Deselect all animation channels 00186 * - data: pointer to datatype, as contained in bAnimContext 00187 * - datatype: the type of data that 'data' represents (eAnimCont_Types) 00188 * - test: check if deselecting instead of selecting 00189 * - sel: eAnimChannels_SetFlag; 00190 */ 00191 void ANIM_deselect_anim_channels (bAnimContext *ac, void *data, short datatype, short test, short sel) 00192 { 00193 ListBase anim_data = {NULL, NULL}; 00194 bAnimListElem *ale; 00195 int filter; 00196 00197 /* filter data */ 00198 /* NOTE: no list visible, otherwise, we get dangling */ 00199 filter= ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS; 00200 ANIM_animdata_filter(ac, &anim_data, filter, data, datatype); 00201 00202 /* See if we should be selecting or deselecting */ 00203 if (test) { 00204 for (ale= anim_data.first; ale; ale= ale->next) { 00205 if (sel == 0) 00206 break; 00207 00208 switch (ale->type) { 00209 case ANIMTYPE_SCENE: 00210 if (ale->flag & SCE_DS_SELECTED) 00211 sel= ACHANNEL_SETFLAG_CLEAR; 00212 break; 00213 case ANIMTYPE_OBJECT: 00214 #if 0 /* for now, do not take object selection into account, since it gets too annoying */ 00215 if (ale->flag & SELECT) 00216 sel= ACHANNEL_SETFLAG_CLEAR; 00217 #endif 00218 break; 00219 case ANIMTYPE_GROUP: 00220 if (ale->flag & AGRP_SELECTED) 00221 sel= ACHANNEL_SETFLAG_CLEAR; 00222 break; 00223 case ANIMTYPE_FCURVE: 00224 if (ale->flag & FCURVE_SELECTED) 00225 sel= ACHANNEL_SETFLAG_CLEAR; 00226 break; 00227 case ANIMTYPE_SHAPEKEY: 00228 if (ale->flag & KEYBLOCK_SEL) 00229 sel= ACHANNEL_SETFLAG_CLEAR; 00230 break; 00231 case ANIMTYPE_NLATRACK: 00232 if (ale->flag & NLATRACK_SELECTED) 00233 sel= ACHANNEL_SETFLAG_CLEAR; 00234 break; 00235 00236 case ANIMTYPE_FILLACTD: /* Action Expander */ 00237 case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ 00238 case ANIMTYPE_DSLAM: 00239 case ANIMTYPE_DSCAM: 00240 case ANIMTYPE_DSCUR: 00241 case ANIMTYPE_DSSKEY: 00242 case ANIMTYPE_DSWOR: 00243 case ANIMTYPE_DSPART: 00244 case ANIMTYPE_DSMBALL: 00245 case ANIMTYPE_DSARM: 00246 case ANIMTYPE_DSMESH: 00247 case ANIMTYPE_DSNTREE: 00248 case ANIMTYPE_DSTEX: 00249 case ANIMTYPE_DSLAT: 00250 case ANIMTYPE_DSSPK: 00251 { 00252 if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) 00253 sel= ACHANNEL_SETFLAG_CLEAR; 00254 } 00255 break; 00256 00257 case ANIMTYPE_GPLAYER: 00258 if (ale->flag & GP_LAYER_SELECT) 00259 sel= ACHANNEL_SETFLAG_CLEAR; 00260 break; 00261 } 00262 } 00263 } 00264 00265 /* Now set the flags */ 00266 for (ale= anim_data.first; ale; ale= ale->next) { 00267 switch (ale->type) { 00268 case ANIMTYPE_SCENE: 00269 { 00270 Scene *scene= (Scene *)ale->data; 00271 00272 ACHANNEL_SET_FLAG(scene, sel, SCE_DS_SELECTED); 00273 00274 if (scene->adt) { 00275 ACHANNEL_SET_FLAG(scene, sel, ADT_UI_SELECTED); 00276 } 00277 } 00278 break; 00279 case ANIMTYPE_OBJECT: 00280 #if 0 /* for now, do not take object selection into account, since it gets too annoying */ 00281 { 00282 Base *base= (Base *)ale->data; 00283 Object *ob= base->object; 00284 00285 ACHANNEL_SET_FLAG(base, sel, SELECT); 00286 ACHANNEL_SET_FLAG(ob, sel, SELECT); 00287 00288 if (ob->adt) { 00289 ACHANNEL_SET_FLAG(ob, sel, ADT_UI_SELECTED); 00290 } 00291 } 00292 #endif 00293 break; 00294 case ANIMTYPE_GROUP: 00295 { 00296 bActionGroup *agrp= (bActionGroup *)ale->data; 00297 00298 ACHANNEL_SET_FLAG(agrp, sel, AGRP_SELECTED); 00299 agrp->flag &= ~AGRP_ACTIVE; 00300 } 00301 break; 00302 case ANIMTYPE_FCURVE: 00303 { 00304 FCurve *fcu= (FCurve *)ale->data; 00305 00306 ACHANNEL_SET_FLAG(fcu, sel, FCURVE_SELECTED); 00307 fcu->flag &= ~FCURVE_ACTIVE; 00308 } 00309 break; 00310 case ANIMTYPE_SHAPEKEY: 00311 { 00312 KeyBlock *kb= (KeyBlock *)ale->data; 00313 00314 ACHANNEL_SET_FLAG(kb, sel, KEYBLOCK_SEL); 00315 } 00316 break; 00317 case ANIMTYPE_NLATRACK: 00318 { 00319 NlaTrack *nlt= (NlaTrack *)ale->data; 00320 00321 ACHANNEL_SET_FLAG(nlt, sel, NLATRACK_SELECTED); 00322 nlt->flag &= ~NLATRACK_ACTIVE; 00323 } 00324 break; 00325 00326 case ANIMTYPE_FILLACTD: /* Action Expander */ 00327 case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ 00328 case ANIMTYPE_DSLAM: 00329 case ANIMTYPE_DSCAM: 00330 case ANIMTYPE_DSCUR: 00331 case ANIMTYPE_DSSKEY: 00332 case ANIMTYPE_DSWOR: 00333 case ANIMTYPE_DSPART: 00334 case ANIMTYPE_DSMBALL: 00335 case ANIMTYPE_DSARM: 00336 case ANIMTYPE_DSMESH: 00337 case ANIMTYPE_DSNTREE: 00338 case ANIMTYPE_DSTEX: 00339 case ANIMTYPE_DSLAT: 00340 case ANIMTYPE_DSSPK: 00341 { 00342 /* need to verify that this data is valid for now */ 00343 if (ale->adt) { 00344 ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED); 00345 ale->adt->flag &= ~ADT_UI_ACTIVE; 00346 } 00347 } 00348 break; 00349 00350 case ANIMTYPE_GPLAYER: 00351 { 00352 bGPDlayer *gpl = (bGPDlayer *)ale->data; 00353 00354 ACHANNEL_SET_FLAG(gpl, sel, GP_LAYER_SELECT); 00355 } 00356 break; 00357 } 00358 } 00359 00360 /* Cleanup */ 00361 BLI_freelistN(&anim_data); 00362 } 00363 00364 /* ---------------------------- Graph Editor ------------------------------------- */ 00365 00366 /* Flush visibility (for Graph Editor) changes up/down hierarchy for changes in the given setting 00367 * - anim_data: list of the all the anim channels that can be chosen 00368 * -> filtered using ANIMFILTER_CHANNELS only, since if we took VISIBLE too, 00369 * then the channels under closed expanders get ignored... 00370 * - ale_setting: the anim channel (not in the anim_data list directly, though occuring there) 00371 * with the new state of the setting that we want flushed up/down the hierarchy 00372 * - setting: type of setting to set 00373 * - on: whether the visibility setting has been enabled or disabled 00374 */ 00375 void ANIM_flush_setting_anim_channels (bAnimContext *ac, ListBase *anim_data, bAnimListElem *ale_setting, int setting, short on) 00376 { 00377 bAnimListElem *ale, *match=NULL; 00378 int prevLevel=0, matchLevel=0; 00379 00380 /* sanity check */ 00381 if (ELEM(NULL, anim_data, anim_data->first)) 00382 return; 00383 00384 /* find the channel that got changed */ 00385 for (ale= anim_data->first; ale; ale= ale->next) { 00386 /* compare data, and type as main way of identifying the channel */ 00387 if ((ale->data == ale_setting->data) && (ale->type == ale_setting->type)) { 00388 /* we also have to check the ID, this is assigned to, since a block may have multiple users */ 00389 // TODO: is the owner-data more revealing? 00390 if (ale->id == ale_setting->id) { 00391 match= ale; 00392 break; 00393 } 00394 } 00395 } 00396 if (match == NULL) { 00397 printf("ERROR: no channel matching the one changed was found \n"); 00398 return; 00399 } 00400 else { 00401 bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale_setting); 00402 00403 if (acf == NULL) { 00404 printf("ERROR: no channel info for the changed channel \n"); 00405 return; 00406 } 00407 00408 /* get the level of the channel that was affected 00409 * - we define the level as simply being the offset for the start of the channel 00410 */ 00411 matchLevel= (acf->get_offset)? acf->get_offset(ac, ale_setting) : 0; 00412 prevLevel= matchLevel; 00413 } 00414 00415 /* flush up? 00416 * 00417 * For Visibility: 00418 * - only flush up if the current state is now enabled (positive 'on' state is default) 00419 * (otherwise, it's too much work to force the parents to be inactive too) 00420 * 00421 * For everything else: 00422 * - only flush up if the current state is now disabled (negative 'off' state is default) 00423 * (otherwise, it's too much work to force the parents to be active too) 00424 */ 00425 if ( ((setting == ACHANNEL_SETTING_VISIBLE) && on) || 00426 ((setting != ACHANNEL_SETTING_VISIBLE) && on==0) ) 00427 { 00428 /* go backwards in the list, until the highest-ranking element (by indention has been covered) */ 00429 for (ale= match->prev; ale; ale= ale->prev) { 00430 bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale); 00431 int level; 00432 00433 /* if no channel info was found, skip, since this type might not have any useful info */ 00434 if (acf == NULL) 00435 continue; 00436 00437 /* get the level of the current channel traversed 00438 * - we define the level as simply being the offset for the start of the channel 00439 */ 00440 level= (acf->get_offset)? acf->get_offset(ac, ale) : 0; 00441 00442 /* if the level is 'less than' (i.e. more important) the level we're matching 00443 * but also 'less than' the level just tried (i.e. only the 1st group above grouped F-Curves, 00444 * when toggling visibility of F-Curves, gets flushed, which should happen if we don't let prevLevel 00445 * get updated below once the first 1st group is found)... 00446 */ 00447 if (level < prevLevel) { 00448 /* flush the new status... */ 00449 ANIM_channel_setting_set(ac, ale, setting, on); 00450 00451 /* store this level as the 'old' level now */ 00452 prevLevel= level; 00453 } 00454 /* if the level is 'greater than' (i.e. less important) than the previous level... */ 00455 else if (level > prevLevel) { 00456 /* if previous level was a base-level (i.e. 0 offset / root of one hierarchy), 00457 * stop here 00458 */ 00459 if (prevLevel == 0) 00460 break; 00461 /* otherwise, this level weaves into another sibling hierarchy to the previous one just 00462 * finished, so skip until we get to the parent of this level 00463 */ 00464 else 00465 continue; 00466 } 00467 } 00468 } 00469 00470 /* flush down (always) */ 00471 { 00472 /* go forwards in the list, until the lowest-ranking element (by indention has been covered) */ 00473 for (ale= match->next; ale; ale= ale->next) { 00474 bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale); 00475 int level; 00476 00477 /* if no channel info was found, skip, since this type might not have any useful info */ 00478 if (acf == NULL) 00479 continue; 00480 00481 /* get the level of the current channel traversed 00482 * - we define the level as simply being the offset for the start of the channel 00483 */ 00484 level= (acf->get_offset)? acf->get_offset(ac, ale) : 0; 00485 00486 /* if the level is 'greater than' (i.e. less important) the channel that was changed, 00487 * flush the new status... 00488 */ 00489 if (level > matchLevel) 00490 ANIM_channel_setting_set(ac, ale, setting, on); 00491 /* however, if the level is 'less than or equal to' the channel that was changed, 00492 * (i.e. the current channel is as important if not more important than the changed channel) 00493 * then we should stop, since we've found the last one of the children we should flush 00494 */ 00495 else 00496 break; 00497 00498 /* store this level as the 'old' level now */ 00499 // prevLevel= level; // XXX: prevLevel is unused 00500 } 00501 } 00502 } 00503 00504 /* -------------------------- F-Curves ------------------------------------- */ 00505 00506 /* Delete the given F-Curve from its AnimData block */ 00507 void ANIM_fcurve_delete_from_animdata (bAnimContext *ac, AnimData *adt, FCurve *fcu) 00508 { 00509 /* - if no AnimData, we've got nowhere to remove the F-Curve from 00510 * (this doesn't guarantee that the F-Curve is in there, but at least we tried 00511 * - if no F-Curve, there is nothing to remove 00512 */ 00513 if (ELEM(NULL, adt, fcu)) 00514 return; 00515 00516 /* remove from whatever list it came from 00517 * - Action Group 00518 * - Action 00519 * - Drivers 00520 * - TODO... some others? 00521 */ 00522 if ((ac) && (ac->datatype == ANIMCONT_DRIVERS)) { 00523 /* driver F-Curve */ 00524 BLI_remlink(&adt->drivers, fcu); 00525 } 00526 else if (adt->action) { 00527 /* remove from group or action, whichever one "owns" the F-Curve */ 00528 if (fcu->grp) 00529 action_groups_remove_channel(adt->action, fcu); 00530 else 00531 BLI_remlink(&adt->action->curves, fcu); 00532 00533 /* if action has no more F-Curves as a result of this, unlink it from 00534 * AnimData if it did not come from a NLA Strip being tweaked. 00535 * 00536 * This is done so that we don't have dangling Object+Action entries in 00537 * channel list that are empty, and linger around long after the data they 00538 * are for has disappeared (and probably won't come back). 00539 */ 00540 // XXX: does everybody always want this? 00541 /* XXX: there's a problem where many actions could build up in the file if multiple 00542 * full add/delete cycles are performed on the same objects, but assume that this is rare 00543 */ 00544 if ((adt->action->curves.first == NULL) && (adt->flag & ADT_NLA_EDIT_ON)==0) 00545 { 00546 id_us_min(&adt->action->id); 00547 adt->action = NULL; 00548 } 00549 } 00550 00551 /* free the F-Curve itself */ 00552 free_fcurve(fcu); 00553 } 00554 00555 /* ************************************************************************** */ 00556 /* OPERATORS */ 00557 00558 /* ****************** Operator Utilities ********************************** */ 00559 00560 /* poll callback for being in an Animation Editor channels list region */ 00561 static int animedit_poll_channels_active (bContext *C) 00562 { 00563 ScrArea *sa= CTX_wm_area(C); 00564 00565 /* channels region test */ 00566 // TODO: could enhance with actually testing if channels region? 00567 if (ELEM(NULL, sa, CTX_wm_region(C))) 00568 return 0; 00569 /* animation editor test */ 00570 if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0) 00571 return 0; 00572 00573 return 1; 00574 } 00575 00576 /* poll callback for Animation Editor channels list region + not in NLA-tweakmode for NLA */ 00577 static int animedit_poll_channels_nla_tweakmode_off (bContext *C) 00578 { 00579 ScrArea *sa= CTX_wm_area(C); 00580 Scene *scene = CTX_data_scene(C); 00581 00582 /* channels region test */ 00583 // TODO: could enhance with actually testing if channels region? 00584 if (ELEM(NULL, sa, CTX_wm_region(C))) 00585 return 0; 00586 /* animation editor test */ 00587 if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0) 00588 return 0; 00589 00590 /* NLA TweakMode test */ 00591 if (sa->spacetype == SPACE_NLA) { 00592 if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON)) 00593 return 0; 00594 } 00595 00596 return 1; 00597 } 00598 00599 /* ****************** Rearrange Channels Operator ******************* */ 00600 00601 /* constants for channel rearranging */ 00602 /* WARNING: don't change exising ones without modifying rearrange func accordingly */ 00603 enum { 00604 REARRANGE_ANIMCHAN_TOP= -2, 00605 REARRANGE_ANIMCHAN_UP= -1, 00606 REARRANGE_ANIMCHAN_DOWN= 1, 00607 REARRANGE_ANIMCHAN_BOTTOM= 2 00608 }; 00609 00610 /* defines for rearranging channels */ 00611 static EnumPropertyItem prop_animchannel_rearrange_types[] = { 00612 {REARRANGE_ANIMCHAN_TOP, "TOP", 0, "To Top", ""}, 00613 {REARRANGE_ANIMCHAN_UP, "UP", 0, "Up", ""}, 00614 {REARRANGE_ANIMCHAN_DOWN, "DOWN", 0, "Down", ""}, 00615 {REARRANGE_ANIMCHAN_BOTTOM, "BOTTOM", 0, "To Bottom", ""}, 00616 {0, NULL, 0, NULL, NULL} 00617 }; 00618 00619 /* Reordering "Islands" Defines ----------------------------------- */ 00620 00621 /* Island definition - just a listbase container */ 00622 typedef struct tReorderChannelIsland { 00623 struct tReorderChannelIsland *next, *prev; 00624 00625 ListBase channels; /* channels within this region with the same state */ 00626 int flag; /* eReorderIslandFlag */ 00627 } tReorderChannelIsland; 00628 00629 /* flags for channel reordering islands */ 00630 typedef enum eReorderIslandFlag { 00631 REORDER_ISLAND_SELECTED = (1<<0), /* island is selected */ 00632 REORDER_ISLAND_UNTOUCHABLE = (1<<1), /* island should be ignored */ 00633 REORDER_ISLAND_MOVED = (1<<2) /* island has already been moved */ 00634 } eReorderIslandFlag; 00635 00636 00637 /* Rearrange Methods --------------------------------------------- */ 00638 00639 static short rearrange_island_ok (tReorderChannelIsland *island) 00640 { 00641 /* island must not be untouchable */ 00642 if (island->flag & REORDER_ISLAND_UNTOUCHABLE) 00643 return 0; 00644 00645 /* island should be selected to be moved */ 00646 return (island->flag & REORDER_ISLAND_SELECTED) && !(island->flag & REORDER_ISLAND_MOVED); 00647 } 00648 00649 /* ............................. */ 00650 00651 static short rearrange_island_top (ListBase *list, tReorderChannelIsland *island) 00652 { 00653 if (rearrange_island_ok(island)) { 00654 /* remove from current position */ 00655 BLI_remlink(list, island); 00656 00657 /* make it first element */ 00658 BLI_insertlinkbefore(list, list->first, island); 00659 00660 return 1; 00661 } 00662 00663 return 0; 00664 } 00665 00666 static short rearrange_island_up (ListBase *list, tReorderChannelIsland *island) 00667 { 00668 if (rearrange_island_ok(island)) { 00669 /* moving up = moving before the previous island, otherwise we're in the same place */ 00670 tReorderChannelIsland *prev= island->prev; 00671 00672 if (prev) { 00673 /* remove from current position */ 00674 BLI_remlink(list, island); 00675 00676 /* push it up */ 00677 BLI_insertlinkbefore(list, prev, island); 00678 00679 return 1; 00680 } 00681 } 00682 00683 return 0; 00684 } 00685 00686 static short rearrange_island_down (ListBase *list, tReorderChannelIsland *island) 00687 { 00688 if (rearrange_island_ok(island)) { 00689 /* moving down = moving after the next island, otherwise we're in the same place */ 00690 tReorderChannelIsland *next = island->next; 00691 00692 if (next) { 00693 /* can only move past if next is not untouchable (i.e. nothing can go after it) */ 00694 if ((next->flag & REORDER_ISLAND_UNTOUCHABLE)==0) { 00695 /* remove from current position */ 00696 BLI_remlink(list, island); 00697 00698 /* push it down */ 00699 BLI_insertlinkafter(list, next, island); 00700 00701 return 1; 00702 } 00703 } 00704 /* else: no next channel, so we're at the bottom already, so can't move */ 00705 } 00706 00707 return 0; 00708 } 00709 00710 static short rearrange_island_bottom (ListBase *list, tReorderChannelIsland *island) 00711 { 00712 if (rearrange_island_ok(island)) { 00713 tReorderChannelIsland *last = list->last; 00714 00715 /* remove island from current position */ 00716 BLI_remlink(list, island); 00717 00718 /* add before or after the last channel? */ 00719 if ((last->flag & REORDER_ISLAND_UNTOUCHABLE)==0) { 00720 /* can add after it */ 00721 BLI_addtail(list, island); 00722 } 00723 else { 00724 /* can at most go just before it, since last cannot be moved */ 00725 BLI_insertlinkbefore(list, last, island); 00726 00727 } 00728 00729 return 1; 00730 } 00731 00732 return 0; 00733 } 00734 00735 /* ............................. */ 00736 00737 /* typedef for channel rearranging function 00738 * < list: list that channels belong to 00739 * < island: island to be moved 00740 * > return[0]: whether operation was a success 00741 */ 00742 typedef short (*AnimChanRearrangeFp)(ListBase *list, tReorderChannelIsland *island); 00743 00744 /* get rearranging function, given 'rearrange' mode */ 00745 static AnimChanRearrangeFp rearrange_get_mode_func (short mode) 00746 { 00747 switch (mode) { 00748 case REARRANGE_ANIMCHAN_TOP: 00749 return rearrange_island_top; 00750 case REARRANGE_ANIMCHAN_UP: 00751 return rearrange_island_up; 00752 case REARRANGE_ANIMCHAN_DOWN: 00753 return rearrange_island_down; 00754 case REARRANGE_ANIMCHAN_BOTTOM: 00755 return rearrange_island_bottom; 00756 default: 00757 return NULL; 00758 } 00759 } 00760 00761 /* Rearrange Islands Generics ------------------------------------- */ 00762 00763 /* add channel into list of islands */ 00764 static void rearrange_animchannel_add_to_islands (ListBase *islands, ListBase *srcList, Link *channel, short type) 00765 { 00766 tReorderChannelIsland *island = islands->last; /* always try to add to last island if possible */ 00767 short is_sel=0, is_untouchable=0; 00768 00769 /* get flags - selected and untouchable from the channel */ 00770 switch (type) { 00771 case ANIMTYPE_GROUP: 00772 { 00773 bActionGroup *agrp= (bActionGroup *)channel; 00774 00775 is_sel= SEL_AGRP(agrp); 00776 is_untouchable= (agrp->flag & AGRP_TEMP) != 0; 00777 } 00778 break; 00779 case ANIMTYPE_FCURVE: 00780 { 00781 FCurve *fcu= (FCurve *)channel; 00782 00783 is_sel= SEL_FCU(fcu); 00784 } 00785 break; 00786 case ANIMTYPE_NLATRACK: 00787 { 00788 NlaTrack *nlt= (NlaTrack *)channel; 00789 00790 is_sel= SEL_NLT(nlt); 00791 } 00792 break; 00793 00794 default: 00795 printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %d\n", type); 00796 return; 00797 } 00798 00799 /* do we need to add to a new island? */ 00800 if ((island == NULL) || /* 1) no islands yet */ 00801 ((island->flag & REORDER_ISLAND_SELECTED) == 0) || /* 2) unselected islands have single channels only - to allow up/down movement */ 00802 (is_sel == 0)) /* 3) if channel is unselected, stop existing island (it was either wrong sel status, or full already) */ 00803 { 00804 /* create a new island now */ 00805 island = MEM_callocN(sizeof(tReorderChannelIsland), "tReorderChannelIsland"); 00806 BLI_addtail(islands, island); 00807 00808 if (is_sel) 00809 island->flag |= REORDER_ISLAND_SELECTED; 00810 if (is_untouchable) 00811 island->flag |= REORDER_ISLAND_UNTOUCHABLE; 00812 } 00813 00814 /* add channel to island - need to remove it from its existing list first though */ 00815 BLI_remlink(srcList, channel); 00816 BLI_addtail(&island->channels, channel); 00817 } 00818 00819 /* flatten islands out into a single list again */ 00820 static void rearrange_animchannel_flatten_islands (ListBase *islands, ListBase *srcList) 00821 { 00822 tReorderChannelIsland *island, *isn=NULL; 00823 00824 /* make sure srcList is empty now */ 00825 BLI_assert(srcList->first == NULL); 00826 00827 /* go through merging islands */ 00828 for (island = islands->first; island; island = isn) { 00829 isn = island->next; 00830 00831 /* merge island channels back to main list, then delete the island */ 00832 BLI_movelisttolist(srcList, &island->channels); 00833 BLI_freelinkN(islands, island); 00834 } 00835 } 00836 00837 /* ............................. */ 00838 00839 /* performing rearranging of channels using islands */ 00840 static short rearrange_animchannel_islands (ListBase *list, AnimChanRearrangeFp rearrange_func, short mode, short type) 00841 { 00842 ListBase islands = {NULL, NULL}; 00843 Link *channel, *chanNext=NULL; 00844 short done = 0; 00845 00846 /* don't waste effort on an empty list */ 00847 if (list->first == NULL) 00848 return 0; 00849 00850 /* group channels into islands */ 00851 for (channel = list->first; channel; channel = chanNext) { 00852 chanNext = channel->next; 00853 rearrange_animchannel_add_to_islands(&islands, list, channel, type); 00854 } 00855 00856 /* perform moving of selected islands now, but only if there is more than one of 'em so that something will happen 00857 * - scanning of the list is performed in the opposite direction to the direction we're moving things, so that we 00858 * shouldn't need to encounter items we've moved already 00859 */ 00860 if (islands.first != islands.last) { 00861 tReorderChannelIsland *first = (mode > 0) ? islands.last : islands.first; 00862 tReorderChannelIsland *island, *isn=NULL; 00863 00864 for (island = first; island; island = isn) { 00865 isn = (mode > 0) ? island->prev : island->next; 00866 00867 /* perform rearranging */ 00868 if (rearrange_func(&islands, island)) { 00869 island->flag |= REORDER_ISLAND_MOVED; 00870 done = 1; 00871 } 00872 } 00873 } 00874 00875 /* ungroup islands */ 00876 rearrange_animchannel_flatten_islands(&islands, list); 00877 00878 /* did we do anything? */ 00879 return done; 00880 } 00881 00882 /* NLA Specific Stuff ----------------------------------------------------- */ 00883 00884 /* Change the order NLA Tracks within NLA Stack 00885 * ! NLA tracks are displayed in opposite order, so directions need care 00886 * mode: REARRANGE_ANIMCHAN_* 00887 */ 00888 static void rearrange_nla_channels (bAnimContext *UNUSED(ac), AnimData *adt, short mode) 00889 { 00890 AnimChanRearrangeFp rearrange_func; 00891 00892 /* hack: invert mode so that functions will work in right order */ 00893 mode *= -1; 00894 00895 /* get rearranging function */ 00896 rearrange_func = rearrange_get_mode_func(mode); 00897 if (rearrange_func == NULL) 00898 return; 00899 00900 /* only consider NLA data if it's accessible */ 00901 //if (EXPANDED_DRVD(adt) == 0) 00902 // return; 00903 00904 /* perform rearranging on tracks list */ 00905 rearrange_animchannel_islands(&adt->nla_tracks, rearrange_func, mode, ANIMTYPE_NLATRACK); 00906 } 00907 00908 /* Drivers Specific Stuff ------------------------------------------------- */ 00909 00910 /* Change the order drivers within AnimData block 00911 * mode: REARRANGE_ANIMCHAN_* 00912 */ 00913 static void rearrange_driver_channels (bAnimContext *UNUSED(ac), AnimData *adt, short mode) 00914 { 00915 /* get rearranging function */ 00916 AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode); 00917 00918 if (rearrange_func == NULL) 00919 return; 00920 00921 /* only consider drivers if they're accessible */ 00922 if (EXPANDED_DRVD(adt) == 0) 00923 return; 00924 00925 /* perform rearranging on drivers list (drivers are really just F-Curves) */ 00926 rearrange_animchannel_islands(&adt->drivers, rearrange_func, mode, ANIMTYPE_FCURVE); 00927 } 00928 00929 /* Action Specific Stuff ------------------------------------------------- */ 00930 00931 /* make sure all action-channels belong to a group (and clear action's list) */ 00932 static void split_groups_action_temp (bAction *act, bActionGroup *tgrp) 00933 { 00934 bActionGroup *agrp; 00935 FCurve *fcu; 00936 00937 if (act == NULL) 00938 return; 00939 00940 /* Separate F-Curves into lists per group */ 00941 for (agrp= act->groups.first; agrp; agrp= agrp->next) { 00942 if (agrp->channels.first) { 00943 fcu= agrp->channels.last; 00944 act->curves.first= fcu->next; 00945 00946 fcu= agrp->channels.first; 00947 fcu->prev= NULL; 00948 00949 fcu= agrp->channels.last; 00950 fcu->next= NULL; 00951 } 00952 } 00953 00954 /* Initialise memory for temp-group */ 00955 memset(tgrp, 0, sizeof(bActionGroup)); 00956 tgrp->flag |= (AGRP_EXPANDED|AGRP_TEMP); 00957 BLI_strncpy(tgrp->name, "#TempGroup", sizeof(tgrp->name)); 00958 00959 /* Move any action-channels not already moved, to the temp group */ 00960 if (act->curves.first) { 00961 /* start of list */ 00962 fcu= act->curves.first; 00963 fcu->prev= NULL; 00964 tgrp->channels.first= fcu; 00965 act->curves.first= NULL; 00966 00967 /* end of list */ 00968 fcu= act->curves.last; 00969 fcu->next= NULL; 00970 tgrp->channels.last= fcu; 00971 act->curves.last= NULL; 00972 } 00973 00974 /* Add temp-group to list */ 00975 BLI_addtail(&act->groups, tgrp); 00976 } 00977 00978 /* link lists of channels that groups have */ 00979 static void join_groups_action_temp (bAction *act) 00980 { 00981 bActionGroup *agrp; 00982 00983 for (agrp= act->groups.first; agrp; agrp= agrp->next) { 00984 ListBase tempGroup; 00985 00986 /* add list of channels to action's channels */ 00987 tempGroup= agrp->channels; 00988 BLI_movelisttolist(&act->curves, &agrp->channels); 00989 agrp->channels= tempGroup; 00990 00991 /* clear moved flag */ 00992 agrp->flag &= ~AGRP_MOVED; 00993 00994 /* if temp-group... remove from list (but don't free as it's on the stack!) */ 00995 if (agrp->flag & AGRP_TEMP) { 00996 BLI_remlink(&act->groups, agrp); 00997 break; 00998 } 00999 } 01000 } 01001 01002 /* Change the order of anim-channels within action 01003 * mode: REARRANGE_ANIMCHAN_* 01004 */ 01005 static void rearrange_action_channels (bAnimContext *ac, bAction *act, short mode) 01006 { 01007 bActionGroup tgrp; 01008 short do_channels; 01009 01010 /* get rearranging function */ 01011 AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode); 01012 01013 if (rearrange_func == NULL) 01014 return; 01015 01016 /* make sure we're only operating with groups (vs a mixture of groups+curves) */ 01017 split_groups_action_temp(act, &tgrp); 01018 01019 /* rearrange groups first 01020 * - the group's channels will only get considered if nothing happened when rearranging the groups 01021 * i.e. the rearrange function returned 0 01022 */ 01023 do_channels = rearrange_animchannel_islands(&act->groups, rearrange_func, mode, ANIMTYPE_GROUP) == 0; 01024 01025 if (do_channels) { 01026 bActionGroup *agrp; 01027 01028 for (agrp= act->groups.first; agrp; agrp= agrp->next) { 01029 /* only consider F-Curves if they're visible (group expanded) */ 01030 if (EXPANDED_AGRP(ac, agrp)) { 01031 rearrange_animchannel_islands(&agrp->channels, rearrange_func, mode, ANIMTYPE_FCURVE); 01032 } 01033 } 01034 } 01035 01036 /* assemble lists into one list (and clear moved tags) */ 01037 join_groups_action_temp(act); 01038 } 01039 01040 /* ------------------- */ 01041 01042 static int animchannels_rearrange_exec(bContext *C, wmOperator *op) 01043 { 01044 bAnimContext ac; 01045 short mode; 01046 01047 /* get editor data */ 01048 if (ANIM_animdata_get_context(C, &ac) == 0) 01049 return OPERATOR_CANCELLED; 01050 01051 /* get mode */ 01052 mode= RNA_enum_get(op->ptr, "direction"); 01053 01054 /* method to move channels depends on the editor */ 01055 if (ac.datatype == ANIMCONT_GPENCIL) { 01056 /* Grease Pencil channels */ 01057 printf("Grease Pencil not supported for moving yet\n"); 01058 } 01059 else if (ac.datatype == ANIMCONT_ACTION) { 01060 /* Directly rearrange action's channels */ 01061 rearrange_action_channels(&ac, ac.data, mode); 01062 } 01063 else { 01064 ListBase anim_data = {NULL, NULL}; 01065 bAnimListElem *ale; 01066 int filter; 01067 01068 /* get animdata blocks */ 01069 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA); 01070 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 01071 01072 for (ale = anim_data.first; ale; ale = ale->next) { 01073 AnimData *adt= ale->data; 01074 01075 switch (ac.datatype) { 01076 case ANIMCONT_NLA: /* NLA-tracks only */ 01077 rearrange_nla_channels(&ac, adt, mode); 01078 break; 01079 01080 case ANIMCONT_DRIVERS: /* Drivers list only */ 01081 rearrange_driver_channels(&ac, adt, mode); 01082 break; 01083 01084 case ANIMCONT_SHAPEKEY: // DOUBLE CHECK ME... 01085 01086 default: /* some collection of actions */ 01087 if (adt->action) 01088 rearrange_action_channels(&ac, adt->action, mode); 01089 else if (G.f & G_DEBUG) 01090 printf("Animdata has no action\n"); 01091 break; 01092 } 01093 } 01094 01095 /* free temp data */ 01096 BLI_freelistN(&anim_data); 01097 } 01098 01099 /* send notifier that things have changed */ 01100 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL); 01101 01102 return OPERATOR_FINISHED; 01103 } 01104 01105 static void ANIM_OT_channels_move (wmOperatorType *ot) 01106 { 01107 /* identifiers */ 01108 ot->name= "Move Channels"; 01109 ot->idname= "ANIM_OT_channels_move"; 01110 ot->description = "Rearrange selected animation channels"; 01111 01112 /* api callbacks */ 01113 ot->exec= animchannels_rearrange_exec; 01114 ot->poll= animedit_poll_channels_nla_tweakmode_off; 01115 01116 /* flags */ 01117 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01118 01119 /* props */ 01120 ot->prop= RNA_def_enum(ot->srna, "direction", prop_animchannel_rearrange_types, REARRANGE_ANIMCHAN_DOWN, "Direction", ""); 01121 } 01122 01123 /* ******************** Delete Channel Operator *********************** */ 01124 01125 static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op)) 01126 { 01127 bAnimContext ac; 01128 ListBase anim_data = {NULL, NULL}; 01129 bAnimListElem *ale; 01130 int filter; 01131 01132 /* get editor data */ 01133 if (ANIM_animdata_get_context(C, &ac) == 0) 01134 return OPERATOR_CANCELLED; 01135 01136 /* cannot delete in shapekey */ 01137 if (ac.datatype == ANIMCONT_SHAPEKEY) 01138 return OPERATOR_CANCELLED; 01139 01140 01141 /* do groups only first (unless in Drivers mode, where there are none) */ 01142 if (ac.datatype != ANIMCONT_DRIVERS) { 01143 /* filter data */ 01144 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); 01145 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 01146 01147 /* delete selected groups and their associated channels */ 01148 for (ale= anim_data.first; ale; ale= ale->next) { 01149 /* only groups - don't check other types yet, since they may no-longer exist */ 01150 if (ale->type == ANIMTYPE_GROUP) { 01151 bActionGroup *agrp= (bActionGroup *)ale->data; 01152 AnimData *adt= ale->adt; 01153 FCurve *fcu, *fcn; 01154 01155 /* skip this group if no AnimData available, as we can't safely remove the F-Curves */ 01156 if (adt == NULL) 01157 continue; 01158 01159 /* delete all of the Group's F-Curves, but no others */ 01160 for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcn) { 01161 fcn= fcu->next; 01162 01163 /* remove from group and action, then free */ 01164 action_groups_remove_channel(adt->action, fcu); 01165 free_fcurve(fcu); 01166 } 01167 01168 /* free the group itself */ 01169 if (adt->action) 01170 BLI_freelinkN(&adt->action->groups, agrp); 01171 else 01172 MEM_freeN(agrp); 01173 } 01174 } 01175 01176 /* cleanup */ 01177 BLI_freelistN(&anim_data); 01178 } 01179 01180 /* filter data */ 01181 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS); 01182 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 01183 01184 /* delete selected data channels */ 01185 for (ale= anim_data.first; ale; ale= ale->next) { 01186 switch (ale->type) { 01187 case ANIMTYPE_FCURVE: 01188 { 01189 /* F-Curves if we can identify its parent */ 01190 AnimData *adt= ale->adt; 01191 FCurve *fcu= (FCurve *)ale->data; 01192 01193 /* try to free F-Curve */ 01194 ANIM_fcurve_delete_from_animdata(&ac, adt, fcu); 01195 } 01196 break; 01197 01198 case ANIMTYPE_GPLAYER: 01199 { 01200 /* Grease Pencil layer */ 01201 bGPdata *gpd= (bGPdata *)ale->id; 01202 bGPDlayer *gpl= (bGPDlayer *)ale->data; 01203 01204 /* try to delete the layer's data and the layer itself */ 01205 free_gpencil_frames(gpl); 01206 BLI_freelinkN(&gpd->layers, gpl); 01207 } 01208 break; 01209 } 01210 } 01211 01212 /* cleanup */ 01213 BLI_freelistN(&anim_data); 01214 01215 /* send notifier that things have changed */ 01216 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL); 01217 01218 return OPERATOR_FINISHED; 01219 } 01220 01221 static void ANIM_OT_channels_delete (wmOperatorType *ot) 01222 { 01223 /* identifiers */ 01224 ot->name= "Delete Channels"; 01225 ot->idname= "ANIM_OT_channels_delete"; 01226 ot->description= "Delete all selected animation channels"; 01227 01228 /* api callbacks */ 01229 ot->exec= animchannels_delete_exec; 01230 ot->poll= animedit_poll_channels_active; 01231 01232 /* flags */ 01233 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01234 } 01235 01236 /* ******************** Set Channel Visibility Operator *********************** */ 01237 /* NOTE: this operator is only valid in the Graph Editor channels region */ 01238 01239 static int animchannels_visibility_set_exec(bContext *C, wmOperator *UNUSED(op)) 01240 { 01241 bAnimContext ac; 01242 ListBase anim_data = {NULL, NULL}; 01243 ListBase all_data = {NULL, NULL}; 01244 bAnimListElem *ale; 01245 int filter; 01246 01247 /* get editor data */ 01248 if (ANIM_animdata_get_context(C, &ac) == 0) 01249 return OPERATOR_CANCELLED; 01250 01251 /* get list of all channels that selection may need to be flushed to 01252 * - hierarchy mustn't affect what we have access to here... 01253 */ 01254 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS); 01255 ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype); 01256 01257 /* hide all channels not selected 01258 * - hierarchy matters if we're doing this from the channels region 01259 * since we only want to apply this to channels we can "see", 01260 * and have these affect their relatives 01261 * - but for Graph Editor, this gets used also from main region 01262 * where hierarchy doesn't apply, as for [#21276] 01263 */ 01264 if ((ac.spacetype == SPACE_IPO) && (ac.regiontype != RGN_TYPE_CHANNELS)) { 01265 /* graph editor (case 2) */ 01266 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_UNSEL | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); 01267 } 01268 else { 01269 /* standard case */ 01270 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_UNSEL | ANIMFILTER_NODUPLIS); 01271 } 01272 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 01273 01274 for (ale= anim_data.first; ale; ale= ale->next) { 01275 /* clear setting first */ 01276 ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_CLEAR); 01277 01278 /* now also flush selection status as appropriate 01279 * NOTE: in some cases, this may result in repeat flushing being performed 01280 */ 01281 ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 0); 01282 } 01283 01284 BLI_freelistN(&anim_data); 01285 01286 /* make all the selected channels visible */ 01287 filter= (ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); 01288 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 01289 01290 for (ale= anim_data.first; ale; ale= ale->next) { 01291 /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */ 01292 // TODO: find out why this is the case, and fix that 01293 if (ale->type == ANIMTYPE_OBJECT) 01294 continue; 01295 01296 /* enable the setting */ 01297 ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_ADD); 01298 01299 /* now, also flush selection status up/down as appropriate */ 01300 ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 1); 01301 } 01302 01303 BLI_freelistN(&anim_data); 01304 BLI_freelistN(&all_data); 01305 01306 01307 /* send notifier that things have changed */ 01308 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL); 01309 01310 return OPERATOR_FINISHED; 01311 } 01312 01313 static void ANIM_OT_channels_visibility_set (wmOperatorType *ot) 01314 { 01315 /* identifiers */ 01316 ot->name= "Set Visibility"; 01317 ot->idname= "ANIM_OT_channels_visibility_set"; 01318 ot->description= "Make only the selected animation channels visible in the Graph Editor"; 01319 01320 /* api callbacks */ 01321 ot->exec= animchannels_visibility_set_exec; 01322 ot->poll= ED_operator_graphedit_active; 01323 01324 /* flags */ 01325 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01326 } 01327 01328 01329 /* ******************** Toggle Channel Visibility Operator *********************** */ 01330 /* NOTE: this operator is only valid in the Graph Editor channels region */ 01331 01332 static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *UNUSED(op)) 01333 { 01334 bAnimContext ac; 01335 ListBase anim_data = {NULL, NULL}; 01336 ListBase all_data = {NULL, NULL}; 01337 bAnimListElem *ale; 01338 int filter; 01339 short vis= ACHANNEL_SETFLAG_ADD; 01340 01341 /* get editor data */ 01342 if (ANIM_animdata_get_context(C, &ac) == 0) 01343 return OPERATOR_CANCELLED; 01344 01345 /* get list of all channels that selection may need to be flushed to 01346 * - hierarchy mustn't affect what we have access to here... 01347 */ 01348 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS); 01349 ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype); 01350 01351 /* filter data 01352 * - restrict this to only applying on settings we can get to in the list 01353 */ 01354 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); 01355 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 01356 01357 /* See if we should be making showing all selected or hiding */ 01358 for (ale= anim_data.first; ale; ale= ale->next) { 01359 /* set the setting in the appropriate way (if available) */ 01360 if (ANIM_channel_setting_get(&ac, ale, ACHANNEL_SETTING_VISIBLE)) { 01361 vis= ACHANNEL_SETFLAG_CLEAR; 01362 break; 01363 } 01364 } 01365 01366 /* Now set the flags */ 01367 for (ale= anim_data.first; ale; ale= ale->next) { 01368 /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */ 01369 // TODO: find out why this is the case, and fix that 01370 if (ale->type == ANIMTYPE_OBJECT) 01371 continue; 01372 01373 /* change the setting */ 01374 ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, vis); 01375 01376 /* now, also flush selection status up/down as appropriate */ 01377 ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, (vis == ACHANNEL_SETFLAG_ADD)); 01378 } 01379 01380 /* cleanup */ 01381 BLI_freelistN(&anim_data); 01382 BLI_freelistN(&all_data); 01383 01384 /* send notifier that things have changed */ 01385 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL); 01386 01387 return OPERATOR_FINISHED; 01388 } 01389 01390 static void ANIM_OT_channels_visibility_toggle (wmOperatorType *ot) 01391 { 01392 /* identifiers */ 01393 ot->name= "Toggle Visibility"; 01394 ot->idname= "ANIM_OT_channels_visibility_toggle"; 01395 ot->description= "Toggle visibility in Graph Editor of all selected animation channels"; 01396 01397 /* api callbacks */ 01398 ot->exec= animchannels_visibility_toggle_exec; 01399 ot->poll= ED_operator_graphedit_active; 01400 01401 /* flags */ 01402 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01403 } 01404 01405 /* ********************** Set Flags Operator *********************** */ 01406 01407 /* defines for setting animation-channel flags */ 01408 static EnumPropertyItem prop_animchannel_setflag_types[] = { 01409 {ACHANNEL_SETFLAG_TOGGLE, "TOGGLE", 0, "Toggle", ""}, 01410 {ACHANNEL_SETFLAG_CLEAR, "DISABLE", 0, "Disable", ""}, 01411 {ACHANNEL_SETFLAG_ADD, "ENABLE", 0, "Enable", ""}, 01412 {ACHANNEL_SETFLAG_INVERT, "INVERT", 0, "Invert", ""}, 01413 {0, NULL, 0, NULL, NULL} 01414 }; 01415 01416 /* defines for set animation-channel settings */ 01417 // TODO: could add some more types, but those are really quite dependent on the mode... 01418 static EnumPropertyItem prop_animchannel_settings_types[] = { 01419 {ACHANNEL_SETTING_PROTECT, "PROTECT", 0, "Protect", ""}, 01420 {ACHANNEL_SETTING_MUTE, "MUTE", 0, "Mute", ""}, 01421 {0, NULL, 0, NULL, NULL} 01422 }; 01423 01424 01425 /* ------------------- */ 01426 01427 /* Set/clear a particular flag (setting) for all selected + visible channels 01428 * setting: the setting to modify 01429 * mode: eAnimChannels_SetFlag 01430 * onlysel: only selected channels get the flag set 01431 */ 01432 // TODO: enable a setting which turns flushing on/off? 01433 static void setflag_anim_channels (bAnimContext *ac, short setting, short mode, short onlysel, short flush) 01434 { 01435 ListBase anim_data = {NULL, NULL}; 01436 ListBase all_data = {NULL, NULL}; 01437 bAnimListElem *ale; 01438 int filter; 01439 01440 /* filter data that we need if flush is on */ 01441 if (flush) { 01442 /* get list of all channels that selection may need to be flushed to 01443 * - hierarchy visibility needs to be ignored so that settings can get flushed 01444 * "down" inside closed containers 01445 */ 01446 filter= ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS; 01447 ANIM_animdata_filter(ac, &all_data, filter, ac->data, ac->datatype); 01448 } 01449 01450 /* filter data that we're working on 01451 * - hierarchy matters if we're doing this from the channels region 01452 * since we only want to apply this to channels we can "see", 01453 * and have these affect their relatives 01454 * - but for Graph Editor, this gets used also from main region 01455 * where hierarchy doesn't apply [#21276] 01456 */ 01457 if ((ac->spacetype == SPACE_IPO) && (ac->regiontype != RGN_TYPE_CHANNELS)) { 01458 /* graph editor (case 2) */ 01459 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS); 01460 } 01461 else { 01462 /* standard case */ 01463 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS); 01464 } 01465 if (onlysel) filter |= ANIMFILTER_SEL; 01466 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 01467 01468 /* if toggling, check if disable or enable */ 01469 if (mode == ACHANNEL_SETFLAG_TOGGLE) { 01470 /* default to turn all on, unless we encounter one that's on... */ 01471 mode= ACHANNEL_SETFLAG_ADD; 01472 01473 /* see if we should turn off instead... */ 01474 for (ale= anim_data.first; ale; ale= ale->next) { 01475 /* set the setting in the appropriate way (if available) */ 01476 if (ANIM_channel_setting_get(ac, ale, setting) > 0) { 01477 mode= ACHANNEL_SETFLAG_CLEAR; 01478 break; 01479 } 01480 } 01481 } 01482 01483 /* apply the setting */ 01484 for (ale= anim_data.first; ale; ale= ale->next) { 01485 /* skip channel if setting is not available */ 01486 if (ANIM_channel_setting_get(ac, ale, setting) == -1) 01487 continue; 01488 01489 /* set the setting in the appropriate way */ 01490 ANIM_channel_setting_set(ac, ale, setting, mode); 01491 01492 /* if flush status... */ 01493 if (flush) 01494 ANIM_flush_setting_anim_channels(ac, &all_data, ale, setting, mode); 01495 } 01496 01497 BLI_freelistN(&anim_data); 01498 BLI_freelistN(&all_data); 01499 } 01500 01501 /* ------------------- */ 01502 01503 static int animchannels_setflag_exec(bContext *C, wmOperator *op) 01504 { 01505 bAnimContext ac; 01506 short mode, setting; 01507 short flush=1; 01508 01509 /* get editor data */ 01510 if (ANIM_animdata_get_context(C, &ac) == 0) 01511 return OPERATOR_CANCELLED; 01512 01513 /* mode (eAnimChannels_SetFlag), setting (eAnimChannel_Settings) */ 01514 mode= RNA_enum_get(op->ptr, "mode"); 01515 setting= RNA_enum_get(op->ptr, "type"); 01516 01517 /* check if setting is flushable */ 01518 if (setting == ACHANNEL_SETTING_EXPAND) 01519 flush= 0; 01520 01521 /* modify setting 01522 * - only selected channels are affected 01523 */ 01524 setflag_anim_channels(&ac, setting, mode, 1, flush); 01525 01526 /* send notifier that things have changed */ 01527 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL); 01528 01529 return OPERATOR_FINISHED; 01530 } 01531 01532 01533 static void ANIM_OT_channels_setting_enable (wmOperatorType *ot) 01534 { 01535 /* identifiers */ 01536 ot->name= "Enable Channel Setting"; 01537 ot->idname= "ANIM_OT_channels_setting_enable"; 01538 ot->description= "Enable specified setting on all selected animation channels"; 01539 01540 /* api callbacks */ 01541 ot->invoke= WM_menu_invoke; 01542 ot->exec= animchannels_setflag_exec; 01543 ot->poll= animedit_poll_channels_active; 01544 01545 /* flags */ 01546 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01547 01548 /* props */ 01549 /* flag-setting mode */ 01550 RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_ADD, "Mode", ""); 01551 /* setting to set */ 01552 ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", ""); 01553 } 01554 01555 static void ANIM_OT_channels_setting_disable (wmOperatorType *ot) 01556 { 01557 /* identifiers */ 01558 ot->name= "Disable Channel Setting"; 01559 ot->idname= "ANIM_OT_channels_setting_disable"; 01560 ot->description= "Disable specified setting on all selected animation channels"; 01561 01562 /* api callbacks */ 01563 ot->invoke= WM_menu_invoke; 01564 ot->exec= animchannels_setflag_exec; 01565 ot->poll= animedit_poll_channels_active; 01566 01567 /* flags */ 01568 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01569 01570 /* props */ 01571 /* flag-setting mode */ 01572 RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_CLEAR, "Mode", ""); 01573 /* setting to set */ 01574 ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", ""); 01575 } 01576 01577 static void ANIM_OT_channels_setting_invert (wmOperatorType *ot) 01578 { 01579 /* identifiers */ 01580 ot->name= "Invert Channel Setting"; 01581 ot->idname= "ANIM_OT_channels_setting_toggle"; 01582 ot->description= "Invert specified setting on all selected animation channels"; 01583 01584 /* api callbacks */ 01585 ot->invoke= WM_menu_invoke; 01586 ot->exec= animchannels_setflag_exec; 01587 ot->poll= animedit_poll_channels_active; 01588 01589 /* flags */ 01590 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01591 01592 /* props */ 01593 /* flag-setting mode */ 01594 RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_INVERT, "Mode", ""); 01595 /* setting to set */ 01596 ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", ""); 01597 } 01598 01599 static void ANIM_OT_channels_setting_toggle (wmOperatorType *ot) 01600 { 01601 /* identifiers */ 01602 ot->name= "Toggle Channel Setting"; 01603 ot->idname= "ANIM_OT_channels_setting_toggle"; 01604 ot->description= "Toggle specified setting on all selected animation channels"; 01605 01606 /* api callbacks */ 01607 ot->invoke= WM_menu_invoke; 01608 ot->exec= animchannels_setflag_exec; 01609 ot->poll= animedit_poll_channels_active; 01610 01611 /* flags */ 01612 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01613 01614 /* props */ 01615 /* flag-setting mode */ 01616 RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", ""); 01617 /* setting to set */ 01618 ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", ""); 01619 } 01620 01621 static void ANIM_OT_channels_editable_toggle (wmOperatorType *ot) 01622 { 01623 /* identifiers */ 01624 ot->name= "Toggle Channel Editability"; 01625 ot->idname= "ANIM_OT_channels_editable_toggle"; 01626 ot->description= "Toggle editability of selected channels"; 01627 01628 /* api callbacks */ 01629 ot->exec= animchannels_setflag_exec; 01630 ot->poll= animedit_poll_channels_active; 01631 01632 /* flags */ 01633 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01634 01635 /* props */ 01636 /* flag-setting mode */ 01637 RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", ""); 01638 /* setting to set */ 01639 RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, ACHANNEL_SETTING_PROTECT, "Type", ""); 01640 } 01641 01642 /* ********************** Expand Channels Operator *********************** */ 01643 01644 static int animchannels_expand_exec (bContext *C, wmOperator *op) 01645 { 01646 bAnimContext ac; 01647 short onlysel= 1; 01648 01649 /* get editor data */ 01650 if (ANIM_animdata_get_context(C, &ac) == 0) 01651 return OPERATOR_CANCELLED; 01652 01653 /* only affect selected channels? */ 01654 if (RNA_boolean_get(op->ptr, "all")) 01655 onlysel= 0; 01656 01657 /* modify setting */ 01658 setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_ADD, onlysel, 0); 01659 01660 /* send notifier that things have changed */ 01661 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL); 01662 01663 return OPERATOR_FINISHED; 01664 } 01665 01666 static void ANIM_OT_channels_expand (wmOperatorType *ot) 01667 { 01668 /* identifiers */ 01669 ot->name= "Expand Channels"; 01670 ot->idname= "ANIM_OT_channels_expand"; 01671 ot->description= "Expand (i.e. open) all selected expandable animation channels"; 01672 01673 /* api callbacks */ 01674 ot->exec= animchannels_expand_exec; 01675 ot->poll= animedit_poll_channels_active; 01676 01677 /* flags */ 01678 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01679 01680 /* props */ 01681 ot->prop= RNA_def_boolean(ot->srna, "all", 1, "All", "Expand all channels (not just selected ones)"); 01682 } 01683 01684 /* ********************** Collapse Channels Operator *********************** */ 01685 01686 static int animchannels_collapse_exec (bContext *C, wmOperator *op) 01687 { 01688 bAnimContext ac; 01689 short onlysel= 1; 01690 01691 /* get editor data */ 01692 if (ANIM_animdata_get_context(C, &ac) == 0) 01693 return OPERATOR_CANCELLED; 01694 01695 /* only affect selected channels? */ 01696 if (RNA_boolean_get(op->ptr, "all")) 01697 onlysel= 0; 01698 01699 /* modify setting */ 01700 setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_CLEAR, onlysel, 0); 01701 01702 /* send notifier that things have changed */ 01703 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL); 01704 01705 return OPERATOR_FINISHED; 01706 } 01707 01708 static void ANIM_OT_channels_collapse (wmOperatorType *ot) 01709 { 01710 /* identifiers */ 01711 ot->name= "Collapse Channels"; 01712 ot->idname= "ANIM_OT_channels_collapse"; 01713 ot->description= "Collapse (i.e. close) all selected expandable animation channels"; 01714 01715 /* api callbacks */ 01716 ot->exec= animchannels_collapse_exec; 01717 ot->poll= animedit_poll_channels_active; 01718 01719 /* flags */ 01720 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01721 01722 /* props */ 01723 ot->prop= RNA_def_boolean(ot->srna, "all", 1, "All", "Collapse all channels (not just selected ones)"); 01724 } 01725 01726 /* ******************* Reenable Disabled Operator ******************* */ 01727 01728 static int animchannels_enable_poll (bContext *C) 01729 { 01730 ScrArea *sa= CTX_wm_area(C); 01731 01732 /* channels region test */ 01733 // TODO: could enhance with actually testing if channels region? 01734 if (ELEM(NULL, sa, CTX_wm_region(C))) 01735 return 0; 01736 01737 /* animation editor test - Action/Dopesheet/etc. and Graph only */ 01738 if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO) == 0) 01739 return 0; 01740 01741 return 1; 01742 } 01743 01744 static int animchannels_enable_exec (bContext *C, wmOperator *UNUSED(op)) 01745 { 01746 bAnimContext ac; 01747 01748 ListBase anim_data = {NULL, NULL}; 01749 bAnimListElem *ale; 01750 int filter; 01751 01752 /* get editor data */ 01753 if (ANIM_animdata_get_context(C, &ac) == 0) 01754 return OPERATOR_CANCELLED; 01755 01756 /* filter data */ 01757 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS); 01758 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 01759 01760 /* loop through filtered data and clean curves */ 01761 for (ale= anim_data.first; ale; ale= ale->next) { 01762 FCurve *fcu = (FCurve *)ale->data; 01763 01764 /* remove disabled flags from F-Curves */ 01765 fcu->flag &= ~FCURVE_DISABLED; 01766 01767 /* for drivers, let's do the same too */ 01768 if (fcu->driver) 01769 fcu->driver->flag &= ~DRIVER_FLAG_INVALID; 01770 01771 /* tag everything for updates - in particular, this is needed to get drivers working again */ 01772 ANIM_list_elem_update(ac.scene, ale); 01773 } 01774 01775 /* free temp data */ 01776 BLI_freelistN(&anim_data); 01777 01778 /* send notifier that things have changed */ 01779 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL); 01780 01781 return OPERATOR_FINISHED; 01782 } 01783 01784 static void ANIM_OT_channels_fcurves_enable (wmOperatorType *ot) 01785 { 01786 /* identifiers */ 01787 ot->name= "Revive Disabled F-Curves"; 01788 ot->idname= "ANIM_OT_channels_fcurves_enable"; 01789 ot->description= "Clears 'disabled' tag from all F-Curves to get broken F-Curves working again"; 01790 01791 /* api callbacks */ 01792 ot->exec= animchannels_enable_exec; 01793 ot->poll= animchannels_enable_poll; 01794 01795 /* flags */ 01796 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01797 } 01798 01799 /* ********************** Select All Operator *********************** */ 01800 01801 static int animchannels_deselectall_exec (bContext *C, wmOperator *op) 01802 { 01803 bAnimContext ac; 01804 01805 /* get editor data */ 01806 if (ANIM_animdata_get_context(C, &ac) == 0) 01807 return OPERATOR_CANCELLED; 01808 01809 /* 'standard' behaviour - check if selected, then apply relevant selection */ 01810 if (RNA_boolean_get(op->ptr, "invert")) 01811 ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 0, ACHANNEL_SETFLAG_TOGGLE); 01812 else 01813 ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_ADD); 01814 01815 /* send notifier that things have changed */ 01816 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_SELECTED, NULL); 01817 01818 return OPERATOR_FINISHED; 01819 } 01820 01821 static void ANIM_OT_channels_select_all_toggle (wmOperatorType *ot) 01822 { 01823 /* identifiers */ 01824 ot->name= "Select All"; 01825 ot->idname= "ANIM_OT_channels_select_all_toggle"; 01826 ot->description= "Toggle selection of all animation channels"; 01827 01828 /* api callbacks */ 01829 ot->exec= animchannels_deselectall_exec; 01830 ot->poll= animedit_poll_channels_nla_tweakmode_off; 01831 01832 /* flags */ 01833 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01834 01835 /* props */ 01836 ot->prop= RNA_def_boolean(ot->srna, "invert", 0, "Invert", ""); 01837 } 01838 01839 /* ******************** Borderselect Operator *********************** */ 01840 01841 static void borderselect_anim_channels (bAnimContext *ac, rcti *rect, short selectmode) 01842 { 01843 ListBase anim_data = {NULL, NULL}; 01844 bAnimListElem *ale; 01845 int filter; 01846 01847 SpaceNla *snla = (SpaceNla *)ac->sl; 01848 View2D *v2d= &ac->ar->v2d; 01849 rctf rectf; 01850 float ymin, ymax; 01851 01852 /* set initial y extents */ 01853 if (ac->datatype == ANIMCONT_NLA) { 01854 ymin = (float)(-NLACHANNEL_HEIGHT(snla)); 01855 ymax = 0.0f; 01856 } 01857 else { 01858 ymin = 0.0f; 01859 ymax = (float)(-ACHANNEL_HEIGHT); 01860 } 01861 01862 /* convert border-region to view coordinates */ 01863 UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin+2, &rectf.xmin, &rectf.ymin); 01864 UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax-2, &rectf.xmax, &rectf.ymax); 01865 01866 /* filter data */ 01867 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); 01868 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 01869 01870 /* loop over data, doing border select */ 01871 for (ale= anim_data.first; ale; ale= ale->next) { 01872 if (ac->datatype == ANIMCONT_NLA) 01873 ymin= ymax - NLACHANNEL_STEP(snla); 01874 else 01875 ymin= ymax - ACHANNEL_STEP; 01876 01877 /* if channel is within border-select region, alter it */ 01878 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) { 01879 /* set selection flags only */ 01880 ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, selectmode); 01881 01882 /* type specific actions */ 01883 switch (ale->type) { 01884 case ANIMTYPE_GROUP: 01885 { 01886 bActionGroup *agrp= (bActionGroup *)ale->data; 01887 01888 /* always clear active flag after doing this */ 01889 agrp->flag &= ~AGRP_ACTIVE; 01890 } 01891 break; 01892 case ANIMTYPE_NLATRACK: 01893 { 01894 NlaTrack *nlt= (NlaTrack *)ale->data; 01895 01896 /* for now, it's easier just to do this here manually, as defining a new type 01897 * currently adds complications when doing other stuff 01898 */ 01899 ACHANNEL_SET_FLAG(nlt, selectmode, NLATRACK_SELECTED); 01900 } 01901 break; 01902 } 01903 } 01904 01905 /* set minimum extent to be the maximum of the next channel */ 01906 ymax= ymin; 01907 } 01908 01909 /* cleanup */ 01910 BLI_freelistN(&anim_data); 01911 } 01912 01913 /* ------------------- */ 01914 01915 static int animchannels_borderselect_exec(bContext *C, wmOperator *op) 01916 { 01917 bAnimContext ac; 01918 rcti rect; 01919 short selectmode=0; 01920 int gesture_mode, extend; 01921 01922 /* get editor data */ 01923 if (ANIM_animdata_get_context(C, &ac) == 0) 01924 return OPERATOR_CANCELLED; 01925 01926 /* get settings from operator */ 01927 rect.xmin= RNA_int_get(op->ptr, "xmin"); 01928 rect.ymin= RNA_int_get(op->ptr, "ymin"); 01929 rect.xmax= RNA_int_get(op->ptr, "xmax"); 01930 rect.ymax= RNA_int_get(op->ptr, "ymax"); 01931 01932 gesture_mode= RNA_int_get(op->ptr, "gesture_mode"); 01933 extend= RNA_boolean_get(op->ptr, "extend"); 01934 01935 if(!extend) 01936 ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_CLEAR); 01937 01938 if (gesture_mode == GESTURE_MODAL_SELECT) 01939 selectmode = ACHANNEL_SETFLAG_ADD; 01940 else 01941 selectmode = ACHANNEL_SETFLAG_CLEAR; 01942 01943 /* apply borderselect animation channels */ 01944 borderselect_anim_channels(&ac, &rect, selectmode); 01945 01946 /* send notifier that things have changed */ 01947 WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_SELECTED, NULL); 01948 01949 return OPERATOR_FINISHED; 01950 } 01951 01952 static void ANIM_OT_channels_select_border(wmOperatorType *ot) 01953 { 01954 /* identifiers */ 01955 ot->name= "Border Select"; 01956 ot->idname= "ANIM_OT_channels_select_border"; 01957 ot->description= "Select all animation channels within the specified region"; 01958 01959 /* api callbacks */ 01960 ot->invoke= WM_border_select_invoke; 01961 ot->exec= animchannels_borderselect_exec; 01962 ot->modal= WM_border_select_modal; 01963 ot->cancel= WM_border_select_cancel; 01964 01965 ot->poll= animedit_poll_channels_nla_tweakmode_off; 01966 01967 /* flags */ 01968 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01969 01970 /* rna */ 01971 WM_operator_properties_gesture_border(ot, TRUE); 01972 } 01973 01974 /* ******************* Rename Operator ***************************** */ 01975 /* Allow renaming some channels by clicking on them */ 01976 01977 static void rename_anim_channels (bAnimContext *ac, int channel_index) 01978 { 01979 ListBase anim_data = {NULL, NULL}; 01980 bAnimChannelType *acf; 01981 bAnimListElem *ale; 01982 int filter; 01983 01984 /* get the channel that was clicked on */ 01985 /* filter channels */ 01986 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); 01987 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 01988 01989 /* get channel from index */ 01990 ale= BLI_findlink(&anim_data, channel_index); 01991 if (ale == NULL) { 01992 /* channel not found */ 01993 if (G.f & G_DEBUG) 01994 printf("Error: animation channel (index = %d) not found in rename_anim_channels() \n", channel_index); 01995 01996 BLI_freelistN(&anim_data); 01997 return; 01998 } 01999 02000 /* check that channel can be renamed */ 02001 acf = ANIM_channel_get_typeinfo(ale); 02002 if (acf && acf->name_prop) { 02003 PointerRNA ptr; 02004 PropertyRNA *prop; 02005 02006 /* ok if we can get name property to edit from this channel */ 02007 if (acf->name_prop(ale, &ptr, &prop)) { 02008 /* actually showing the rename textfield is done on redraw, 02009 * so here we just store the index of this channel in the 02010 * dopesheet data, which will get utilised when drawing the 02011 * channel... 02012 * 02013 * +1 factor is for backwards compat issues 02014 */ 02015 if (ac->ads) { 02016 ac->ads->renameIndex = channel_index + 1; 02017 } 02018 } 02019 } 02020 02021 /* free temp data and tag for refresh */ 02022 BLI_freelistN(&anim_data); 02023 ED_region_tag_redraw(ac->ar); 02024 } 02025 02026 static int animchannels_rename_invoke (bContext *C, wmOperator *UNUSED(op), wmEvent *evt) 02027 { 02028 bAnimContext ac; 02029 ARegion *ar; 02030 View2D *v2d; 02031 int channel_index; 02032 float x, y; 02033 02034 /* get editor data */ 02035 if (ANIM_animdata_get_context(C, &ac) == 0) 02036 return OPERATOR_CANCELLED; 02037 02038 /* get useful pointers from animation context data */ 02039 ar= ac.ar; 02040 v2d= &ar->v2d; 02041 02042 /* figure out which channel user clicked in 02043 * Note: although channels technically start at y= ACHANNEL_FIRST, we need to adjust by half a channel's height 02044 * so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use 02045 * ACHANNEL_HEIGHT_HALF. 02046 */ 02047 UI_view2d_region_to_view(v2d, evt->mval[0], evt->mval[1], &x, &y); 02048 02049 if (ac.datatype == ANIMCONT_NLA) { 02050 SpaceNla *snla = (SpaceNla *)ac.sl; 02051 UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index); 02052 } 02053 else { 02054 UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index); 02055 } 02056 02057 /* handle click */ 02058 rename_anim_channels(&ac, channel_index); 02059 02060 return OPERATOR_FINISHED; 02061 } 02062 02063 static void ANIM_OT_channels_rename (wmOperatorType *ot) 02064 { 02065 /* identifiers */ 02066 ot->name= "Rename Channels"; 02067 ot->idname= "ANIM_OT_channels_rename"; 02068 ot->description= "Rename animation channel under mouse"; 02069 02070 /* api callbacks */ 02071 ot->invoke= animchannels_rename_invoke; 02072 ot->poll= animedit_poll_channels_active; 02073 } 02074 02075 /* ******************** Mouse-Click Operator *********************** */ 02076 /* Handle selection changes due to clicking on channels. Settings will get caught by UI code... */ 02077 02078 static int mouse_anim_channels (bAnimContext *ac, float UNUSED(x), int channel_index, short selectmode) 02079 { 02080 ListBase anim_data = {NULL, NULL}; 02081 bAnimListElem *ale; 02082 int filter; 02083 int notifierFlags = 0; 02084 02085 /* get the channel that was clicked on */ 02086 /* filter channels */ 02087 filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); 02088 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 02089 02090 /* get channel from index */ 02091 ale= BLI_findlink(&anim_data, channel_index); 02092 if (ale == NULL) { 02093 /* channel not found */ 02094 if (G.f & G_DEBUG) 02095 printf("Error: animation channel (index = %d) not found in mouse_anim_channels() \n", channel_index); 02096 02097 BLI_freelistN(&anim_data); 02098 return 0; 02099 } 02100 02101 /* selectmode -1 is a special case for ActionGroups only, which selects all of the channels underneath it only... */ 02102 // TODO: should this feature be extended to work with other channel types too? 02103 if ((selectmode == -1) && (ale->type != ANIMTYPE_GROUP)) { 02104 /* normal channels should not behave normally in this case */ 02105 BLI_freelistN(&anim_data); 02106 return 0; 02107 } 02108 02109 /* action to take depends on what channel we've got */ 02110 // WARNING: must keep this in sync with the equivalent function in nla_channels.c 02111 switch (ale->type) { 02112 case ANIMTYPE_SCENE: 02113 { 02114 Scene *sce= (Scene *)ale->data; 02115 AnimData *adt= sce->adt; 02116 02117 /* set selection status */ 02118 if (selectmode == SELECT_INVERT) { 02119 /* swap select */ 02120 sce->flag ^= SCE_DS_SELECTED; 02121 if (adt) adt->flag ^= ADT_UI_SELECTED; 02122 } 02123 else { 02124 sce->flag |= SCE_DS_SELECTED; 02125 if (adt) adt->flag |= ADT_UI_SELECTED; 02126 } 02127 02128 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED); 02129 } 02130 break; 02131 case ANIMTYPE_OBJECT: 02132 { 02133 bDopeSheet *ads= (bDopeSheet *)ac->data; 02134 Scene *sce= (Scene *)ads->source; 02135 Base *base= (Base *)ale->data; 02136 Object *ob= base->object; 02137 AnimData *adt= ob->adt; 02138 02139 /* set selection status */ 02140 if (selectmode == SELECT_INVERT) { 02141 /* swap select */ 02142 base->flag ^= SELECT; 02143 ob->flag= base->flag; 02144 02145 if (adt) adt->flag ^= ADT_UI_SELECTED; 02146 } 02147 else { 02148 Base *b; 02149 02150 /* deselect all */ 02151 // TODO: should this deselect all other types of channels too? 02152 for (b= sce->base.first; b; b= b->next) { 02153 b->flag &= ~SELECT; 02154 b->object->flag= b->flag; 02155 if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED|ADT_UI_ACTIVE); 02156 } 02157 02158 /* select object now */ 02159 base->flag |= SELECT; 02160 ob->flag |= SELECT; 02161 if (adt) adt->flag |= ADT_UI_SELECTED; 02162 } 02163 02164 if ((adt) && (adt->flag & ADT_UI_SELECTED)) 02165 adt->flag |= ADT_UI_ACTIVE; 02166 02167 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED); 02168 } 02169 break; 02170 02171 case ANIMTYPE_FILLACTD: /* Action Expander */ 02172 case ANIMTYPE_DSMAT: /* Datablock AnimData Expanders */ 02173 case ANIMTYPE_DSLAM: 02174 case ANIMTYPE_DSCAM: 02175 case ANIMTYPE_DSCUR: 02176 case ANIMTYPE_DSSKEY: 02177 case ANIMTYPE_DSWOR: 02178 case ANIMTYPE_DSPART: 02179 case ANIMTYPE_DSMBALL: 02180 case ANIMTYPE_DSARM: 02181 case ANIMTYPE_DSMESH: 02182 case ANIMTYPE_DSNTREE: 02183 case ANIMTYPE_DSTEX: 02184 case ANIMTYPE_DSLAT: 02185 case ANIMTYPE_DSSPK: 02186 { 02187 /* sanity checking... */ 02188 if (ale->adt) { 02189 /* select/deselect */ 02190 if (selectmode == SELECT_INVERT) { 02191 /* inverse selection status of this AnimData block only */ 02192 ale->adt->flag ^= ADT_UI_SELECTED; 02193 } 02194 else { 02195 /* select AnimData block by itself */ 02196 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); 02197 ale->adt->flag |= ADT_UI_SELECTED; 02198 } 02199 02200 /* set active? */ 02201 if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) 02202 ale->adt->flag |= ADT_UI_ACTIVE; 02203 } 02204 02205 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED); 02206 } 02207 break; 02208 02209 case ANIMTYPE_GROUP: 02210 { 02211 bActionGroup *agrp= (bActionGroup *)ale->data; 02212 02213 /* select/deselect group */ 02214 if (selectmode == SELECT_INVERT) { 02215 /* inverse selection status of this group only */ 02216 agrp->flag ^= AGRP_SELECTED; 02217 } 02218 else if (selectmode == -1) { 02219 /* select all in group (and deselect everthing else) */ 02220 FCurve *fcu; 02221 02222 /* deselect all other channels */ 02223 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); 02224 02225 /* only select channels in group and group itself */ 02226 for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next) 02227 fcu->flag |= FCURVE_SELECTED; 02228 agrp->flag |= AGRP_SELECTED; 02229 } 02230 else { 02231 /* select group by itself */ 02232 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); 02233 agrp->flag |= AGRP_SELECTED; 02234 } 02235 02236 /* if group is selected now, make group the 'active' one in the visible list */ 02237 if (agrp->flag & AGRP_SELECTED) 02238 ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); 02239 02240 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED); 02241 } 02242 break; 02243 case ANIMTYPE_FCURVE: 02244 { 02245 FCurve *fcu= (FCurve *)ale->data; 02246 02247 /* select/deselect */ 02248 if (selectmode == SELECT_INVERT) { 02249 /* inverse selection status of this F-Curve only */ 02250 fcu->flag ^= FCURVE_SELECTED; 02251 } 02252 else { 02253 /* select F-Curve by itself */ 02254 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); 02255 fcu->flag |= FCURVE_SELECTED; 02256 } 02257 02258 /* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */ 02259 if (fcu->flag & FCURVE_SELECTED) 02260 ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE); 02261 02262 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED); 02263 } 02264 break; 02265 case ANIMTYPE_SHAPEKEY: 02266 { 02267 KeyBlock *kb= (KeyBlock *)ale->data; 02268 02269 /* select/deselect */ 02270 if (selectmode == SELECT_INVERT) { 02271 /* inverse selection status of this ShapeKey only */ 02272 kb->flag ^= KEYBLOCK_SEL; 02273 } 02274 else { 02275 /* select ShapeKey by itself */ 02276 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); 02277 kb->flag |= KEYBLOCK_SEL; 02278 } 02279 02280 notifierFlags |= (ND_ANIMCHAN|NA_SELECTED); 02281 } 02282 break; 02283 case ANIMTYPE_GPDATABLOCK: 02284 { 02285 bGPdata *gpd= (bGPdata *)ale->data; 02286 02287 /* toggle expand 02288 * - although the triangle widget already allows this, the whole channel can also be used for this purpose 02289 */ 02290 gpd->flag ^= GP_DATA_EXPAND; 02291 02292 notifierFlags |= (ND_ANIMCHAN|NA_EDITED); 02293 } 02294 break; 02295 case ANIMTYPE_GPLAYER: 02296 { 02297 bGPDlayer *gpl= (bGPDlayer *)ale->data; 02298 02299 /* select/deselect */ 02300 if (selectmode == SELECT_INVERT) { 02301 /* invert selection status of this layer only */ 02302 gpl->flag ^= GP_LAYER_SELECT; 02303 } 02304 else { 02305 /* select layer by itself */ 02306 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); 02307 gpl->flag |= GP_LAYER_SELECT; 02308 } 02309 02310 notifierFlags |= (ND_ANIMCHAN|NA_EDITED); 02311 } 02312 break; 02313 default: 02314 if (G.f & G_DEBUG) 02315 printf("Error: Invalid channel type in mouse_anim_channels() \n"); 02316 } 02317 02318 /* free channels */ 02319 BLI_freelistN(&anim_data); 02320 02321 /* return notifier flags */ 02322 return notifierFlags; 02323 } 02324 02325 /* ------------------- */ 02326 02327 /* handle clicking */ 02328 static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event) 02329 { 02330 bAnimContext ac; 02331 ARegion *ar; 02332 View2D *v2d; 02333 int channel_index; 02334 int notifierFlags = 0; 02335 short selectmode; 02336 float x, y; 02337 02338 02339 /* get editor data */ 02340 if (ANIM_animdata_get_context(C, &ac) == 0) 02341 return OPERATOR_CANCELLED; 02342 02343 /* get useful pointers from animation context data */ 02344 ar= ac.ar; 02345 v2d= &ar->v2d; 02346 02347 /* select mode is either replace (deselect all, then add) or add/extend */ 02348 if (RNA_boolean_get(op->ptr, "extend")) 02349 selectmode= SELECT_INVERT; 02350 else if (RNA_boolean_get(op->ptr, "children_only")) 02351 selectmode= -1; /* this is a bit of a special case for ActionGroups only... should it be removed or extended to all instead? */ 02352 else 02353 selectmode= SELECT_REPLACE; 02354 02355 /* figure out which channel user clicked in 02356 * Note: although channels technically start at y= ACHANNEL_FIRST, we need to adjust by half a channel's height 02357 * so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use 02358 * ACHANNEL_HEIGHT_HALF. 02359 */ 02360 UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y); 02361 UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index); 02362 02363 /* handle mouse-click in the relevant channel then */ 02364 notifierFlags= mouse_anim_channels(&ac, x, channel_index, selectmode); 02365 02366 /* set notifier that things have changed */ 02367 WM_event_add_notifier(C, NC_ANIMATION|notifierFlags, NULL); 02368 02369 return OPERATOR_FINISHED; 02370 } 02371 02372 static void ANIM_OT_channels_click (wmOperatorType *ot) 02373 { 02374 /* identifiers */ 02375 ot->name= "Mouse Click on Channels"; 02376 ot->idname= "ANIM_OT_channels_click"; 02377 ot->description= "Handle mouse-clicks over animation channels"; 02378 02379 /* api callbacks */ 02380 ot->invoke= animchannels_mouseclick_invoke; 02381 ot->poll= animedit_poll_channels_active; 02382 02383 /* flags */ 02384 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 02385 02386 /* id-props */ 02387 RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY 02388 RNA_def_boolean(ot->srna, "children_only", 0, "Select Children Only", ""); // CTRLKEY|SHIFTKEY 02389 } 02390 02391 /* ************************************************************************** */ 02392 /* Operator Registration */ 02393 02394 void ED_operatortypes_animchannels(void) 02395 { 02396 WM_operatortype_append(ANIM_OT_channels_select_all_toggle); 02397 WM_operatortype_append(ANIM_OT_channels_select_border); 02398 02399 WM_operatortype_append(ANIM_OT_channels_click); 02400 WM_operatortype_append(ANIM_OT_channels_rename); 02401 02402 WM_operatortype_append(ANIM_OT_channels_setting_enable); 02403 WM_operatortype_append(ANIM_OT_channels_setting_disable); 02404 WM_operatortype_append(ANIM_OT_channels_setting_invert); 02405 WM_operatortype_append(ANIM_OT_channels_setting_toggle); 02406 02407 WM_operatortype_append(ANIM_OT_channels_delete); 02408 02409 // XXX does this need to be a separate operator? 02410 WM_operatortype_append(ANIM_OT_channels_editable_toggle); 02411 02412 WM_operatortype_append(ANIM_OT_channels_move); 02413 02414 WM_operatortype_append(ANIM_OT_channels_expand); 02415 WM_operatortype_append(ANIM_OT_channels_collapse); 02416 02417 WM_operatortype_append(ANIM_OT_channels_visibility_toggle); 02418 WM_operatortype_append(ANIM_OT_channels_visibility_set); 02419 02420 WM_operatortype_append(ANIM_OT_channels_fcurves_enable); 02421 } 02422 02423 // TODO: check on a poll callback for this, to get hotkeys into menus 02424 void ED_keymap_animchannels(wmKeyConfig *keyconf) 02425 { 02426 wmKeyMap *keymap = WM_keymap_find(keyconf, "Animation Channels", 0, 0); 02427 wmKeyMapItem *kmi; 02428 02429 /* selection */ 02430 /* click-select */ 02431 // XXX for now, only leftmouse.... 02432 WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, 0, 0); 02433 RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", TRUE); 02434 RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_CTRL|KM_SHIFT, 0)->ptr, "children_only", TRUE); 02435 02436 /* rename */ 02437 WM_keymap_add_item(keymap, "ANIM_OT_channels_rename", LEFTMOUSE, KM_PRESS, KM_CTRL, 0); 02438 02439 /* deselect all */ 02440 WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", AKEY, KM_PRESS, 0, 0); 02441 RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", TRUE); 02442 02443 /* borderselect */ 02444 WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", BKEY, KM_PRESS, 0, 0); 02445 WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", EVT_TWEAK_L, KM_ANY, 0, 0); 02446 02447 /* delete */ 02448 WM_keymap_add_item(keymap, "ANIM_OT_channels_delete", XKEY, KM_PRESS, 0, 0); 02449 WM_keymap_add_item(keymap, "ANIM_OT_channels_delete", DELKEY, KM_PRESS, 0, 0); 02450 02451 /* settings */ 02452 WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_toggle", WKEY, KM_PRESS, KM_SHIFT, 0); 02453 WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_enable", WKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0); 02454 WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_disable", WKEY, KM_PRESS, KM_ALT, 0); 02455 02456 /* settings - specialized hotkeys */ 02457 WM_keymap_add_item(keymap, "ANIM_OT_channels_editable_toggle", TABKEY, KM_PRESS, 0, 0); 02458 02459 /* expand/collapse */ 02460 WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, 0, 0); 02461 WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, 0, 0); 02462 02463 kmi = WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, KM_CTRL, 0); 02464 RNA_boolean_set(kmi->ptr, "all", FALSE); 02465 kmi = WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, KM_CTRL, 0); 02466 RNA_boolean_set(kmi->ptr, "all", FALSE); 02467 02468 /* rearranging */ 02469 RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEUPKEY, KM_PRESS, 0, 0)->ptr, "direction", REARRANGE_ANIMCHAN_UP); 02470 RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEDOWNKEY, KM_PRESS, 0, 0)->ptr, "direction", REARRANGE_ANIMCHAN_DOWN); 02471 RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEUPKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "direction", REARRANGE_ANIMCHAN_TOP); 02472 RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "direction", REARRANGE_ANIMCHAN_BOTTOM); 02473 02474 /* Graph Editor only */ 02475 WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_set", VKEY, KM_PRESS, 0, 0); 02476 WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_toggle", VKEY, KM_PRESS, KM_SHIFT, 0); 02477 } 02478 02479 /* ************************************************************************** */