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