|
Blender
V2.59
|
00001 /* 00002 * $Id: graph_select.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) 2008 Blender Foundation 00021 * 00022 * Contributor(s): Joshua Leung 00023 * 00024 * ***** END GPL LICENSE BLOCK ***** 00025 */ 00026 00032 #include <math.h> 00033 #include <stdlib.h> 00034 #include <string.h> 00035 #include <float.h> 00036 00037 #include "MEM_guardedalloc.h" 00038 00039 #include "BLI_blenlib.h" 00040 #include "BLI_math.h" 00041 #include "BLI_utildefines.h" 00042 00043 #include "DNA_anim_types.h" 00044 #include "DNA_object_types.h" 00045 #include "DNA_screen_types.h" 00046 #include "DNA_scene_types.h" 00047 #include "DNA_space_types.h" 00048 00049 #include "RNA_access.h" 00050 #include "RNA_define.h" 00051 00052 #include "BKE_fcurve.h" 00053 #include "BKE_nla.h" 00054 #include "BKE_context.h" 00055 00056 #include "UI_view2d.h" 00057 00058 #include "ED_anim_api.h" 00059 #include "ED_keyframes_edit.h" 00060 #include "ED_markers.h" 00061 00062 #include "WM_api.h" 00063 #include "WM_types.h" 00064 00065 #include "graph_intern.h" 00066 00067 00068 /* ************************************************************************** */ 00069 /* KEYFRAMES STUFF */ 00070 00071 /* ******************** Deselect All Operator ***************************** */ 00072 /* This operator works in one of three ways: 00073 * 1) (de)select all (AKEY) - test if select all or deselect all 00074 * 2) invert all (CTRL-IKEY) - invert selection of all keyframes 00075 * 3) (de)select all - no testing is done; only for use internal tools as normal function... 00076 */ 00077 00078 /* Deselects keyframes in the Graph Editor 00079 * - This is called by the deselect all operator, as well as other ones! 00080 * 00081 * - test: check if select or deselect all 00082 * - sel: how to select keyframes 00083 * 0 = deselect 00084 * 1 = select 00085 * 2 = invert 00086 */ 00087 static void deselect_graph_keys (bAnimContext *ac, short test, short sel) 00088 { 00089 ListBase anim_data = {NULL, NULL}; 00090 bAnimListElem *ale; 00091 int filter; 00092 00093 SpaceIpo *sipo= (SpaceIpo *)ac->sa->spacedata.first; 00094 KeyframeEditData ked= {{NULL}}; 00095 KeyframeEditFunc test_cb, sel_cb; 00096 00097 /* determine type-based settings */ 00098 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); 00099 00100 /* filter data */ 00101 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00102 00103 /* init BezTriple looping data */ 00104 test_cb= ANIM_editkeyframes_ok(BEZT_OK_SELECTED); 00105 00106 /* See if we should be selecting or deselecting */ 00107 if (test) { 00108 for (ale= anim_data.first; ale; ale= ale->next) { 00109 if (ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, test_cb, NULL)) { 00110 sel= SELECT_SUBTRACT; 00111 break; 00112 } 00113 } 00114 } 00115 00116 /* convert sel to selectmode, and use that to get editor */ 00117 sel_cb= ANIM_editkeyframes_select(sel); 00118 00119 /* Now set the flags */ 00120 for (ale= anim_data.first; ale; ale= ale->next) { 00121 FCurve *fcu= (FCurve *)ale->key_data; 00122 00123 /* Keyframes First */ 00124 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, sel_cb, NULL); 00125 00126 /* only change selection of channel when the visibility of keyframes doesn't depend on this */ 00127 if ((sipo->flag & SIPO_SELCUVERTSONLY) == 0) { 00128 /* deactivate the F-Curve, and deselect if deselecting keyframes. 00129 * otherwise select the F-Curve too since we've selected all the keyframes 00130 */ 00131 if (sel == SELECT_SUBTRACT) 00132 fcu->flag &= ~FCURVE_SELECTED; 00133 else 00134 fcu->flag |= FCURVE_SELECTED; 00135 } 00136 00137 /* always deactivate all F-Curves if we perform batch ops for selection */ 00138 fcu->flag &= ~FCURVE_ACTIVE; 00139 } 00140 00141 /* Cleanup */ 00142 BLI_freelistN(&anim_data); 00143 } 00144 00145 /* ------------------- */ 00146 00147 static int graphkeys_deselectall_exec(bContext *C, wmOperator *op) 00148 { 00149 bAnimContext ac; 00150 00151 /* get editor data */ 00152 if (ANIM_animdata_get_context(C, &ac) == 0) 00153 return OPERATOR_CANCELLED; 00154 00155 /* 'standard' behaviour - check if selected, then apply relevant selection */ 00156 if (RNA_boolean_get(op->ptr, "invert")) 00157 deselect_graph_keys(&ac, 0, SELECT_INVERT); 00158 else 00159 deselect_graph_keys(&ac, 1, SELECT_ADD); 00160 00161 /* set notifier that things have changed */ 00162 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_SELECTED, NULL); 00163 00164 return OPERATOR_FINISHED; 00165 } 00166 00167 void GRAPH_OT_select_all_toggle (wmOperatorType *ot) 00168 { 00169 /* identifiers */ 00170 ot->name= "Select All"; 00171 ot->idname= "GRAPH_OT_select_all_toggle"; 00172 ot->description= "Toggle selection of all keyframes"; 00173 00174 /* api callbacks */ 00175 ot->exec= graphkeys_deselectall_exec; 00176 ot->poll= graphop_visible_keyframes_poll; 00177 00178 /* flags */ 00179 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; 00180 00181 /* props */ 00182 ot->prop= RNA_def_boolean(ot->srna, "invert", 0, "Invert", ""); 00183 } 00184 00185 /* ******************** Border Select Operator **************************** */ 00186 /* This operator currently works in one of three ways: 00187 * -> BKEY - 1) all keyframes within region are selected (validation with BEZT_OK_REGION) 00188 * -> ALT-BKEY - depending on which axis of the region was larger... 00189 * -> 2) x-axis, so select all frames within frame range (validation with BEZT_OK_FRAMERANGE) 00190 * -> 3) y-axis, so select all frames within channels that region included (validation with BEZT_OK_VALUERANGE) 00191 */ 00192 00193 /* Borderselect only selects keyframes now, as overshooting handles often get caught too, 00194 * which means that they may be inadvertantly moved as well. However, incl_handles overrides 00195 * this, and allow handles to be considered independently too. 00196 * Also, for convenience, handles should get same status as keyframe (if it was within bounds). 00197 */ 00198 static void borderselect_graphkeys (bAnimContext *ac, rcti rect, short mode, short selectmode, short incl_handles) 00199 { 00200 ListBase anim_data = {NULL, NULL}; 00201 bAnimListElem *ale; 00202 int filter; 00203 00204 SpaceIpo *sipo= (SpaceIpo *)ac->sa->spacedata.first; 00205 KeyframeEditData ked; 00206 KeyframeEditFunc ok_cb, select_cb; 00207 View2D *v2d= &ac->ar->v2d; 00208 rctf rectf; 00209 00210 /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */ 00211 UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin); 00212 UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax); 00213 00214 /* filter data */ 00215 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_NODUPLIS); 00216 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00217 00218 /* get beztriple editing/validation funcs */ 00219 select_cb= ANIM_editkeyframes_select(selectmode); 00220 ok_cb= ANIM_editkeyframes_ok(mode); 00221 00222 /* init editing data */ 00223 memset(&ked, 0, sizeof(KeyframeEditData)); 00224 ked.data= &rectf; 00225 00226 /* treat handles separately? */ 00227 if (incl_handles) 00228 ked.iterflags |= KEYFRAME_ITER_INCL_HANDLES; 00229 00230 /* loop over data, doing border select */ 00231 for (ale= anim_data.first; ale; ale= ale->next) { 00232 AnimData *adt= ANIM_nla_mapping_get(ac, ale); 00233 FCurve *fcu= (FCurve *)ale->key_data; 00234 00235 /* apply unit corrections */ 00236 ANIM_unit_mapping_apply_fcurve(ac->scene, ale->id, ale->key_data, ANIM_UNITCONV_ONLYKEYS); 00237 00238 /* apply NLA mapping to all the keyframes, since it's easier than trying to 00239 * guess when a callback might use something different 00240 */ 00241 if (adt) 00242 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, incl_handles==0); 00243 00244 /* set horizontal range (if applicable) 00245 * NOTE: these values are only used for x-range and y-range but not region 00246 * (which uses ked.data, i.e. rectf) 00247 */ 00248 if (mode != BEZT_OK_VALUERANGE) { 00249 ked.f1= rectf.xmin; 00250 ked.f2= rectf.xmax; 00251 } 00252 else { 00253 ked.f1= rectf.ymin; 00254 ked.f2= rectf.ymax; 00255 } 00256 00257 /* firstly, check if any keyframes will be hit by this */ 00258 if (ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, ok_cb, NULL)) { 00259 /* select keyframes that are in the appropriate places */ 00260 ANIM_fcurve_keyframes_loop(&ked, fcu, ok_cb, select_cb, NULL); 00261 00262 /* only change selection of channel when the visibility of keyframes doesn't depend on this */ 00263 if ((sipo->flag & SIPO_SELCUVERTSONLY) == 0) { 00264 /* select the curve too now that curve will be touched */ 00265 if (selectmode == SELECT_ADD) 00266 fcu->flag |= FCURVE_SELECTED; 00267 } 00268 } 00269 00270 /* un-apply NLA mapping from all the keyframes */ 00271 if (adt) 00272 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, incl_handles==0); 00273 00274 /* unapply unit corrections */ 00275 ANIM_unit_mapping_apply_fcurve(ac->scene, ale->id, ale->key_data, ANIM_UNITCONV_RESTORE|ANIM_UNITCONV_ONLYKEYS); 00276 } 00277 00278 /* cleanup */ 00279 BLI_freelistN(&anim_data); 00280 } 00281 00282 /* ------------------- */ 00283 00284 static int graphkeys_borderselect_exec(bContext *C, wmOperator *op) 00285 { 00286 bAnimContext ac; 00287 rcti rect; 00288 short mode=0, selectmode=0; 00289 short incl_handles; 00290 00291 /* get editor data */ 00292 if (ANIM_animdata_get_context(C, &ac) == 0) 00293 return OPERATOR_CANCELLED; 00294 00295 /* get select mode 00296 * - 'gesture_mode' from the operator specifies how to select 00297 * - 'include_handles' from the operator specifies whether to include handles in the selection 00298 */ 00299 if (RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_SELECT) 00300 selectmode= SELECT_ADD; 00301 else 00302 selectmode= SELECT_SUBTRACT; 00303 00304 incl_handles = RNA_boolean_get(op->ptr, "include_handles"); 00305 00306 /* get settings from operator */ 00307 rect.xmin= RNA_int_get(op->ptr, "xmin"); 00308 rect.ymin= RNA_int_get(op->ptr, "ymin"); 00309 rect.xmax= RNA_int_get(op->ptr, "xmax"); 00310 rect.ymax= RNA_int_get(op->ptr, "ymax"); 00311 00312 /* selection 'mode' depends on whether borderselect region only matters on one axis */ 00313 if (RNA_boolean_get(op->ptr, "axis_range")) { 00314 /* mode depends on which axis of the range is larger to determine which axis to use 00315 * - checking this in region-space is fine, as it's fundamentally still going to be a different rect size 00316 * - the frame-range select option is favoured over the channel one (x over y), as frame-range one is often 00317 * used for tweaking timing when "blocking", while channels is not that useful... 00318 */ 00319 if ((rect.xmax - rect.xmin) >= (rect.ymax - rect.ymin)) 00320 mode= BEZT_OK_FRAMERANGE; 00321 else 00322 mode= BEZT_OK_VALUERANGE; 00323 } 00324 else 00325 mode= BEZT_OK_REGION; 00326 00327 /* apply borderselect action */ 00328 borderselect_graphkeys(&ac, rect, mode, selectmode, incl_handles); 00329 00330 /* send notifier that keyframe selection has changed */ 00331 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_SELECTED, NULL); 00332 00333 return OPERATOR_FINISHED; 00334 } 00335 00336 void GRAPH_OT_select_border(wmOperatorType *ot) 00337 { 00338 /* identifiers */ 00339 ot->name= "Border Select"; 00340 ot->idname= "GRAPH_OT_select_border"; 00341 ot->description= "Select all keyframes within the specified region"; 00342 00343 /* api callbacks */ 00344 ot->invoke= WM_border_select_invoke; 00345 ot->exec= graphkeys_borderselect_exec; 00346 ot->modal= WM_border_select_modal; 00347 ot->cancel= WM_border_select_cancel; 00348 00349 ot->poll= graphop_visible_keyframes_poll; 00350 00351 /* flags */ 00352 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; 00353 00354 /* rna */ 00355 WM_operator_properties_gesture_border(ot, FALSE); 00356 00357 ot->prop= RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", ""); 00358 RNA_def_boolean(ot->srna, "include_handles", 0, "Include Handles", "Are handles tested individually against the selection criteria"); 00359 } 00360 00361 /* ******************** Column Select Operator **************************** */ 00362 /* This operator works in one of four ways: 00363 * - 1) select all keyframes in the same frame as a selected one (KKEY) 00364 * - 2) select all keyframes in the same frame as the current frame marker (CTRL-KKEY) 00365 * - 3) select all keyframes in the same frame as a selected markers (SHIFT-KKEY) 00366 * - 4) select all keyframes that occur between selected markers (ALT-KKEY) 00367 */ 00368 00369 /* defines for column-select mode */ 00370 static EnumPropertyItem prop_column_select_types[] = { 00371 {GRAPHKEYS_COLUMNSEL_KEYS, "KEYS", 0, "On Selected Keyframes", ""}, 00372 {GRAPHKEYS_COLUMNSEL_CFRA, "CFRA", 0, "On Current Frame", ""}, 00373 {GRAPHKEYS_COLUMNSEL_MARKERS_COLUMN, "MARKERS_COLUMN", 0, "On Selected Markers", ""}, 00374 {GRAPHKEYS_COLUMNSEL_MARKERS_BETWEEN, "MARKERS_BETWEEN", 0, "Between Min/Max Selected Markers", ""}, 00375 {0, NULL, 0, NULL, NULL} 00376 }; 00377 00378 /* ------------------- */ 00379 00380 /* Selects all visible keyframes between the specified markers */ 00381 static void markers_selectkeys_between (bAnimContext *ac) 00382 { 00383 ListBase anim_data = {NULL, NULL}; 00384 bAnimListElem *ale; 00385 int filter; 00386 00387 KeyframeEditFunc ok_cb, select_cb; 00388 KeyframeEditData ked; 00389 float min, max; 00390 00391 /* get extreme markers */ 00392 ED_markers_get_minmax(ac->markers, 1, &min, &max); 00393 min -= 0.5f; 00394 max += 0.5f; 00395 00396 /* get editing funcs + data */ 00397 ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); 00398 select_cb= ANIM_editkeyframes_select(SELECT_ADD); 00399 00400 memset(&ked, 0, sizeof(KeyframeEditData)); 00401 ked.f1= min; 00402 ked.f2= max; 00403 00404 /* filter data */ 00405 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); 00406 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00407 00408 /* select keys in-between */ 00409 for (ale= anim_data.first; ale; ale= ale->next) { 00410 AnimData *adt= ANIM_nla_mapping_get(ac, ale); 00411 00412 if (adt) { 00413 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 00414 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); 00415 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); 00416 } 00417 else { 00418 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); 00419 } 00420 } 00421 00422 /* Cleanup */ 00423 BLI_freelistN(&anim_data); 00424 } 00425 00426 00427 /* Selects all visible keyframes in the same frames as the specified elements */ 00428 static void columnselect_graph_keys (bAnimContext *ac, short mode) 00429 { 00430 ListBase anim_data= {NULL, NULL}; 00431 bAnimListElem *ale; 00432 int filter; 00433 00434 Scene *scene= ac->scene; 00435 CfraElem *ce; 00436 KeyframeEditFunc select_cb, ok_cb; 00437 KeyframeEditData ked; 00438 00439 /* initialise keyframe editing data */ 00440 memset(&ked, 0, sizeof(KeyframeEditData)); 00441 00442 /* build list of columns */ 00443 switch (mode) { 00444 case GRAPHKEYS_COLUMNSEL_KEYS: /* list of selected keys */ 00445 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); 00446 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00447 00448 for (ale= anim_data.first; ale; ale= ale->next) 00449 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_to_cfraelem, NULL); 00450 00451 BLI_freelistN(&anim_data); 00452 break; 00453 00454 case GRAPHKEYS_COLUMNSEL_CFRA: /* current frame */ 00455 /* make a single CfraElem for storing this */ 00456 ce= MEM_callocN(sizeof(CfraElem), "cfraElem"); 00457 BLI_addtail(&ked.list, ce); 00458 00459 ce->cfra= (float)CFRA; 00460 break; 00461 00462 case GRAPHKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */ 00463 ED_markers_make_cfra_list(ac->markers, &ked.list, SELECT); 00464 break; 00465 00466 default: /* invalid option */ 00467 return; 00468 } 00469 00470 /* set up BezTriple edit callbacks */ 00471 select_cb= ANIM_editkeyframes_select(SELECT_ADD); 00472 ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME); 00473 00474 /* loop through all of the keys and select additional keyframes 00475 * based on the keys found to be selected above 00476 */ 00477 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); 00478 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00479 00480 for (ale= anim_data.first; ale; ale= ale->next) { 00481 AnimData *adt= ANIM_nla_mapping_get(ac, ale); 00482 00483 /* loop over cfraelems (stored in the KeyframeEditData->list) 00484 * - we need to do this here, as we can apply fewer NLA-mapping conversions 00485 */ 00486 for (ce= ked.list.first; ce; ce= ce->next) { 00487 /* set frame for validation callback to refer to */ 00488 ked.f1= BKE_nla_tweakedit_remap(adt, ce->cfra, NLATIME_CONVERT_UNMAP); 00489 00490 /* select elements with frame number matching cfraelem */ 00491 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); 00492 } 00493 } 00494 00495 /* free elements */ 00496 BLI_freelistN(&ked.list); 00497 BLI_freelistN(&anim_data); 00498 } 00499 00500 /* ------------------- */ 00501 00502 static int graphkeys_columnselect_exec(bContext *C, wmOperator *op) 00503 { 00504 bAnimContext ac; 00505 short mode; 00506 00507 /* get editor data */ 00508 if (ANIM_animdata_get_context(C, &ac) == 0) 00509 return OPERATOR_CANCELLED; 00510 00511 /* action to take depends on the mode */ 00512 mode= RNA_enum_get(op->ptr, "mode"); 00513 00514 if (mode == GRAPHKEYS_COLUMNSEL_MARKERS_BETWEEN) 00515 markers_selectkeys_between(&ac); 00516 else 00517 columnselect_graph_keys(&ac, mode); 00518 00519 /* set notifier that keyframe selection has changed */ 00520 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_SELECTED, NULL); 00521 00522 return OPERATOR_FINISHED; 00523 } 00524 00525 void GRAPH_OT_select_column (wmOperatorType *ot) 00526 { 00527 /* identifiers */ 00528 ot->name= "Select All"; 00529 ot->idname= "GRAPH_OT_select_column"; 00530 ot->description= "Select all keyframes on the specified frame(s)"; 00531 00532 /* api callbacks */ 00533 ot->exec= graphkeys_columnselect_exec; 00534 ot->poll= graphop_visible_keyframes_poll; 00535 00536 /* flags */ 00537 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; 00538 00539 /* props */ 00540 ot->prop= RNA_def_enum(ot->srna, "mode", prop_column_select_types, 0, "Mode", ""); 00541 } 00542 00543 /* ******************** Select Linked Operator *********************** */ 00544 00545 static int graphkeys_select_linked_exec (bContext *C, wmOperator *UNUSED(op)) 00546 { 00547 bAnimContext ac; 00548 00549 ListBase anim_data= {NULL, NULL}; 00550 bAnimListElem *ale; 00551 int filter; 00552 00553 KeyframeEditFunc ok_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED); 00554 KeyframeEditFunc sel_cb = ANIM_editkeyframes_select(SELECT_ADD); 00555 00556 /* get editor data */ 00557 if (ANIM_animdata_get_context(C, &ac) == 0) 00558 return OPERATOR_CANCELLED; 00559 00560 /* loop through all of the keys and select additional keyframes based on these */ 00561 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); 00562 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 00563 00564 for (ale= anim_data.first; ale; ale= ale->next) { 00565 FCurve *fcu= (FCurve *)ale->key_data; 00566 00567 /* check if anything selected? */ 00568 if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, ok_cb, NULL)) { 00569 /* select every keyframe in this curve then */ 00570 ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL); 00571 } 00572 } 00573 00574 /* Cleanup */ 00575 BLI_freelistN(&anim_data); 00576 00577 /* set notifier that keyframe selection has changed */ 00578 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_SELECTED, NULL); 00579 00580 return OPERATOR_FINISHED; 00581 } 00582 00583 void GRAPH_OT_select_linked (wmOperatorType *ot) 00584 { 00585 /* identifiers */ 00586 ot->name = "Select Linked"; 00587 ot->idname= "GRAPH_OT_select_linked"; 00588 ot->description = "Select keyframes occurring the same F-Curves as selected ones"; 00589 00590 /* api callbacks */ 00591 ot->exec= graphkeys_select_linked_exec; 00592 ot->poll= graphop_visible_keyframes_poll; 00593 00594 /* flags */ 00595 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; 00596 } 00597 00598 /* ******************** Select More/Less Operators *********************** */ 00599 00600 /* Common code to perform selection */ 00601 static void select_moreless_graph_keys (bAnimContext *ac, short mode) 00602 { 00603 ListBase anim_data= {NULL, NULL}; 00604 bAnimListElem *ale; 00605 int filter; 00606 00607 KeyframeEditData ked; 00608 KeyframeEditFunc build_cb; 00609 00610 00611 /* init selmap building data */ 00612 build_cb= ANIM_editkeyframes_buildselmap(mode); 00613 memset(&ked, 0, sizeof(KeyframeEditData)); 00614 00615 /* loop through all of the keys and select additional keyframes based on these */ 00616 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); 00617 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00618 00619 for (ale= anim_data.first; ale; ale= ale->next) { 00620 FCurve *fcu= (FCurve *)ale->key_data; 00621 00622 /* only continue if F-Curve has keyframes */ 00623 if (fcu->bezt == NULL) 00624 continue; 00625 00626 /* build up map of whether F-Curve's keyframes should be selected or not */ 00627 ked.data= MEM_callocN(fcu->totvert, "selmap graphEdit"); 00628 ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, build_cb, NULL); 00629 00630 /* based on this map, adjust the selection status of the keyframes */ 00631 ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, bezt_selmap_flush, NULL); 00632 00633 /* free the selmap used here */ 00634 MEM_freeN(ked.data); 00635 ked.data= NULL; 00636 } 00637 00638 /* Cleanup */ 00639 BLI_freelistN(&anim_data); 00640 } 00641 00642 /* ----------------- */ 00643 00644 static int graphkeys_select_more_exec (bContext *C, wmOperator *UNUSED(op)) 00645 { 00646 bAnimContext ac; 00647 00648 /* get editor data */ 00649 if (ANIM_animdata_get_context(C, &ac) == 0) 00650 return OPERATOR_CANCELLED; 00651 00652 /* perform select changes */ 00653 select_moreless_graph_keys(&ac, SELMAP_MORE); 00654 00655 /* set notifier that keyframe selection has changed */ 00656 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_SELECTED, NULL); 00657 00658 return OPERATOR_FINISHED; 00659 } 00660 00661 void GRAPH_OT_select_more (wmOperatorType *ot) 00662 { 00663 /* identifiers */ 00664 ot->name = "Select More"; 00665 ot->idname= "GRAPH_OT_select_more"; 00666 ot->description = "Select keyframes beside already selected ones"; 00667 00668 /* api callbacks */ 00669 ot->exec= graphkeys_select_more_exec; 00670 ot->poll= graphop_visible_keyframes_poll; 00671 00672 /* flags */ 00673 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; 00674 } 00675 00676 /* ----------------- */ 00677 00678 static int graphkeys_select_less_exec (bContext *C, wmOperator *UNUSED(op)) 00679 { 00680 bAnimContext ac; 00681 00682 /* get editor data */ 00683 if (ANIM_animdata_get_context(C, &ac) == 0) 00684 return OPERATOR_CANCELLED; 00685 00686 /* perform select changes */ 00687 select_moreless_graph_keys(&ac, SELMAP_LESS); 00688 00689 /* set notifier that keyframe selection has changed */ 00690 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_SELECTED, NULL); 00691 00692 return OPERATOR_FINISHED; 00693 } 00694 00695 void GRAPH_OT_select_less (wmOperatorType *ot) 00696 { 00697 /* identifiers */ 00698 ot->name = "Select Less"; 00699 ot->idname= "GRAPH_OT_select_less"; 00700 ot->description = "Deselect keyframes on ends of selection islands"; 00701 00702 /* api callbacks */ 00703 ot->exec= graphkeys_select_less_exec; 00704 ot->poll= graphop_visible_keyframes_poll; 00705 00706 /* flags */ 00707 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; 00708 } 00709 00710 /* ******************** Select Left/Right Operator ************************* */ 00711 /* Select keyframes left/right of the current frame indicator */ 00712 00713 /* defines for left-right select tool */ 00714 static EnumPropertyItem prop_graphkeys_leftright_select_types[] = { 00715 {GRAPHKEYS_LRSEL_TEST, "CHECK", 0, "Check if Select Left or Right", ""}, 00716 {GRAPHKEYS_LRSEL_LEFT, "LEFT", 0, "Before current frame", ""}, 00717 {GRAPHKEYS_LRSEL_RIGHT, "RIGHT", 0, "After current frame", ""}, 00718 {0, NULL, 0, NULL, NULL} 00719 }; 00720 00721 /* --------------------------------- */ 00722 00723 static void graphkeys_select_leftright (bAnimContext *ac, short leftright, short select_mode) 00724 { 00725 ListBase anim_data = {NULL, NULL}; 00726 bAnimListElem *ale; 00727 int filter; 00728 00729 KeyframeEditFunc ok_cb, select_cb; 00730 KeyframeEditData ked= {{NULL}}; 00731 Scene *scene= ac->scene; 00732 00733 /* if select mode is replace, deselect all keyframes (and channels) first */ 00734 if (select_mode==SELECT_REPLACE) { 00735 select_mode= SELECT_ADD; 00736 00737 /* deselect all other channels and keyframes */ 00738 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); 00739 deselect_graph_keys(ac, 0, SELECT_SUBTRACT); 00740 } 00741 00742 /* set callbacks and editing data */ 00743 ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); 00744 select_cb= ANIM_editkeyframes_select(select_mode); 00745 00746 if (leftright == GRAPHKEYS_LRSEL_LEFT) { 00747 ked.f1 = MINAFRAMEF; 00748 ked.f2 = (float)(CFRA + 0.1f); 00749 } 00750 else { 00751 ked.f1 = (float)(CFRA - 0.1f); 00752 ked.f2 = MAXFRAMEF; 00753 } 00754 00755 /* filter data */ 00756 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); 00757 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00758 00759 /* select keys */ 00760 for (ale= anim_data.first; ale; ale= ale->next) { 00761 AnimData *adt= ANIM_nla_mapping_get(ac, ale); 00762 00763 if (adt) { 00764 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 00765 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); 00766 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); 00767 } 00768 else 00769 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); 00770 } 00771 00772 /* Cleanup */ 00773 BLI_freelistN(&anim_data); 00774 } 00775 00776 /* ----------------- */ 00777 00778 static int graphkeys_select_leftright_exec (bContext *C, wmOperator *op) 00779 { 00780 bAnimContext ac; 00781 short leftright = RNA_enum_get(op->ptr, "mode"); 00782 short selectmode; 00783 00784 /* get editor data */ 00785 if (ANIM_animdata_get_context(C, &ac) == 0) 00786 return OPERATOR_CANCELLED; 00787 00788 /* select mode is either replace (deselect all, then add) or add/extend */ 00789 if (RNA_boolean_get(op->ptr, "extend")) 00790 selectmode= SELECT_INVERT; 00791 else 00792 selectmode= SELECT_REPLACE; 00793 00794 /* if "test" mode is set, we don't have any info to set this with */ 00795 if (leftright == GRAPHKEYS_LRSEL_TEST) 00796 return OPERATOR_CANCELLED; 00797 00798 /* do the selecting now */ 00799 graphkeys_select_leftright(&ac, leftright, selectmode); 00800 00801 /* set notifier that keyframe selection (and channels too) have changed */ 00802 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|ND_ANIMCHAN|NA_SELECTED, NULL); 00803 00804 return OPERATOR_FINISHED; 00805 } 00806 00807 static int graphkeys_select_leftright_invoke (bContext *C, wmOperator *op, wmEvent *event) 00808 { 00809 bAnimContext ac; 00810 short leftright = RNA_enum_get(op->ptr, "mode"); 00811 00812 /* get editor data */ 00813 if (ANIM_animdata_get_context(C, &ac) == 0) 00814 return OPERATOR_CANCELLED; 00815 00816 /* handle mode-based testing */ 00817 if (leftright == GRAPHKEYS_LRSEL_TEST) { 00818 Scene *scene= ac.scene; 00819 ARegion *ar= ac.ar; 00820 View2D *v2d= &ar->v2d; 00821 float x; 00822 00823 /* determine which side of the current frame mouse is on */ 00824 UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, NULL); 00825 if (x < CFRA) 00826 RNA_enum_set(op->ptr, "mode", GRAPHKEYS_LRSEL_LEFT); 00827 else 00828 RNA_enum_set(op->ptr, "mode", GRAPHKEYS_LRSEL_RIGHT); 00829 } 00830 00831 /* perform selection */ 00832 return graphkeys_select_leftright_exec(C, op); 00833 } 00834 00835 void GRAPH_OT_select_leftright (wmOperatorType *ot) 00836 { 00837 /* identifiers */ 00838 ot->name= "Select Left/Right"; 00839 ot->idname= "GRAPH_OT_select_leftright"; 00840 ot->description= "Select keyframes to the left or the right of the current frame"; 00841 00842 /* api callbacks */ 00843 ot->invoke= graphkeys_select_leftright_invoke; 00844 ot->exec= graphkeys_select_leftright_exec; 00845 ot->poll= graphop_visible_keyframes_poll; 00846 00847 /* flags */ 00848 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00849 00850 /* id-props */ 00851 ot->prop= RNA_def_enum(ot->srna, "mode", prop_graphkeys_leftright_select_types, GRAPHKEYS_LRSEL_TEST, "Mode", ""); 00852 RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); 00853 } 00854 00855 /* ******************** Mouse-Click Select Operator *********************** */ 00856 /* This operator works in one of three ways: 00857 * - 1) keyframe under mouse - no special modifiers 00858 * - 2) all keyframes on the same side of current frame indicator as mouse - ALT modifier 00859 * - 3) column select all keyframes in frame under mouse - CTRL modifier 00860 * 00861 * In addition to these basic options, the SHIFT modifier can be used to toggle the 00862 * selection mode between replacing the selection (without) and inverting the selection (with). 00863 */ 00864 00865 /* temp info for caching handle vertices close */ 00866 typedef struct tNearestVertInfo { 00867 struct tNearestVertInfo *next, *prev; 00868 00869 FCurve *fcu; /* F-Curve that keyframe comes from */ 00870 00871 BezTriple *bezt; /* keyframe to consider */ 00872 FPoint *fpt; /* sample point to consider */ 00873 00874 short hpoint; /* the handle index that we hit (eHandleIndex) */ 00875 short sel; /* whether the handle is selected or not */ 00876 int dist; /* distance from mouse to vert */ 00877 } tNearestVertInfo; 00878 00879 /* Tags for the type of graph vert that we have */ 00880 typedef enum eGraphVertIndex { 00881 NEAREST_HANDLE_LEFT = -1, 00882 NEAREST_HANDLE_KEY, 00883 NEAREST_HANDLE_RIGHT 00884 } eGraphVertIndex; 00885 00886 /* Tolerance for absolute radius (in pixels) of the vert from the cursor to use */ 00887 // TODO: perhaps this should depend a bit on the size that the user set the vertices to be? 00888 #define GVERTSEL_TOL 10 00889 00890 /* ....... */ 00891 00892 /* check if its ok to select a handle */ 00893 // XXX also need to check for int-values only? 00894 static int fcurve_handle_sel_check(SpaceIpo *sipo, BezTriple *bezt) 00895 { 00896 if (sipo->flag & SIPO_NOHANDLES) return 0; 00897 if ((sipo->flag & SIPO_SELVHANDLESONLY) && BEZSELECTED(bezt)==0) return 0; 00898 return 1; 00899 } 00900 00901 /* check if the given vertex is within bounds or not */ 00902 // TODO: should we return if we hit something? 00903 static void nearest_fcurve_vert_store (ListBase *matches, View2D *v2d, FCurve *fcu, BezTriple *bezt, FPoint *fpt, short hpoint, const int mval[2]) 00904 { 00905 /* Keyframes or Samples? */ 00906 if (bezt) { 00907 int screen_co[2], dist; 00908 00909 /* convert from data-space to screen coordinates 00910 * NOTE: hpoint+1 gives us 0,1,2 respectively for each handle, 00911 * needed to access the relevant vertex coordinates in the 3x3 00912 * 'vec' matrix 00913 */ 00914 UI_view2d_view_to_region(v2d, bezt->vec[hpoint+1][0], bezt->vec[hpoint+1][1], &screen_co[0], &screen_co[1]); 00915 00916 /* check if distance from mouse cursor to vert in screen space is within tolerance */ 00917 // XXX: inlined distance calculation, since we cannot do this on ints using the math lib... 00918 //dist = len_v2v2(mval, screen_co); 00919 dist = sqrt((mval[0] - screen_co[0])*(mval[0] - screen_co[0]) + 00920 (mval[1] - screen_co[1])*(mval[1] - screen_co[1])); 00921 00922 if (dist <= GVERTSEL_TOL) { 00923 tNearestVertInfo *nvi = (tNearestVertInfo *)matches->last; 00924 short replace = 0; 00925 00926 /* if there is already a point for the F-Curve, check if this point is closer than that was */ 00927 if ((nvi) && (nvi->fcu == fcu)) { 00928 /* replace if we are closer, or if equal and that one wasn't selected but we are... */ 00929 if ( (nvi->dist > dist) || ((nvi->sel == 0) && BEZSELECTED(bezt)) ) 00930 replace= 1; 00931 } 00932 /* add new if not replacing... */ 00933 if (replace == 0) 00934 nvi = MEM_callocN(sizeof(tNearestVertInfo), "Nearest Graph Vert Info - Bezt"); 00935 00936 /* store values */ 00937 nvi->fcu = fcu; 00938 nvi->bezt = bezt; 00939 nvi->hpoint = hpoint; 00940 nvi->dist = dist; 00941 00942 nvi->sel= BEZSELECTED(bezt); // XXX... should this use the individual verts instead? 00943 00944 /* add to list of matches if appropriate... */ 00945 if (replace == 0) 00946 BLI_addtail(matches, nvi); 00947 } 00948 } 00949 else if (fpt) { 00950 // TODO... 00951 } 00952 } 00953 00954 /* helper for find_nearest_fcurve_vert() - build the list of nearest matches */ 00955 static void get_nearest_fcurve_verts_list (bAnimContext *ac, const int mval[2], ListBase *matches) 00956 { 00957 ListBase anim_data = {NULL, NULL}; 00958 bAnimListElem *ale; 00959 int filter; 00960 00961 SpaceIpo *sipo= (SpaceIpo *)ac->sa->spacedata.first; 00962 View2D *v2d= &ac->ar->v2d; 00963 00964 /* get curves to search through 00965 * - if the option to only show keyframes that belong to selected F-Curves is enabled, 00966 * include the 'only selected' flag... 00967 */ 00968 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); 00969 if (sipo->flag & SIPO_SELCUVERTSONLY) // FIXME: this should really be check for by the filtering code... 00970 filter |= ANIMFILTER_SEL; 00971 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00972 00973 for (ale= anim_data.first; ale; ale= ale->next) { 00974 FCurve *fcu= (FCurve *)ale->key_data; 00975 AnimData *adt= ANIM_nla_mapping_get(ac, ale); 00976 00977 /* apply unit corrections */ 00978 ANIM_unit_mapping_apply_fcurve(ac->scene, ale->id, ale->key_data, 0); 00979 00980 /* apply NLA mapping to all the keyframes */ 00981 if (adt) 00982 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 0); 00983 00984 if (fcu->bezt) { 00985 BezTriple *bezt1=fcu->bezt, *prevbezt=NULL; 00986 int i; 00987 00988 for (i=0; i < fcu->totvert; i++, prevbezt=bezt1, bezt1++) { 00989 /* keyframe */ 00990 nearest_fcurve_vert_store(matches, v2d, fcu, bezt1, NULL, NEAREST_HANDLE_KEY, mval); 00991 00992 /* handles - only do them if they're visible */ 00993 if (fcurve_handle_sel_check(sipo, bezt1) && (fcu->totvert > 1)) { 00994 /* first handle only visible if previous segment had handles */ 00995 if ( (!prevbezt && (bezt1->ipo==BEZT_IPO_BEZ)) || (prevbezt && (prevbezt->ipo==BEZT_IPO_BEZ)) ) 00996 { 00997 nearest_fcurve_vert_store(matches, v2d, fcu, bezt1, NULL, NEAREST_HANDLE_LEFT, mval); 00998 } 00999 01000 /* second handle only visible if this segment is bezier */ 01001 if (bezt1->ipo == BEZT_IPO_BEZ) 01002 { 01003 nearest_fcurve_vert_store(matches, v2d, fcu, bezt1, NULL, NEAREST_HANDLE_RIGHT, mval); 01004 } 01005 } 01006 } 01007 } 01008 else if (fcu->fpt) { 01009 // TODO; do this for samples too 01010 01011 } 01012 01013 /* un-apply NLA mapping from all the keyframes */ 01014 if (adt) 01015 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 0); 01016 01017 /* unapply unit corrections */ 01018 ANIM_unit_mapping_apply_fcurve(ac->scene, ale->id, ale->key_data, ANIM_UNITCONV_RESTORE); 01019 } 01020 01021 /* free channels */ 01022 BLI_freelistN(&anim_data); 01023 } 01024 01025 /* helper for find_nearest_fcurve_vert() - get the best match to use */ 01026 static tNearestVertInfo *get_best_nearest_fcurve_vert (ListBase *matches) 01027 { 01028 tNearestVertInfo *nvi = NULL; 01029 short found = 0; 01030 01031 /* abort if list is empty */ 01032 if (matches->first == NULL) 01033 return NULL; 01034 01035 /* if list only has 1 item, remove it from the list and return */ 01036 if (matches->first == matches->last) { 01037 /* need to remove from the list, otherwise it gets freed and then we can't return it */ 01038 nvi= matches->first; 01039 BLI_remlink(matches, nvi); 01040 01041 return nvi; 01042 } 01043 01044 /* try to find the first selected F-Curve vert, then take the one after it */ 01045 for (nvi = matches->first; nvi; nvi = nvi->next) { 01046 /* which mode of search are we in: find first selected, or find vert? */ 01047 if (found) { 01048 /* just take this vert now that we've found the selected one 01049 * - we'll need to remove this from the list so that it can be returned to the original caller 01050 */ 01051 BLI_remlink(matches, nvi); 01052 return nvi; 01053 } 01054 else { 01055 /* if vert is selected, we've got what we want... */ 01056 if (nvi->sel) 01057 found= 1; 01058 } 01059 } 01060 01061 /* if we're still here, this means that we failed to find anything appropriate in the first pass, 01062 * so just take the first item now... 01063 */ 01064 nvi = matches->first; 01065 BLI_remlink(matches, nvi); 01066 return nvi; 01067 } 01068 01069 /* Find the nearest vertices (either a handle or the keyframe) that are nearest to the mouse cursor (in area coordinates) 01070 * NOTE: the match info found must still be freed 01071 */ 01072 static tNearestVertInfo *find_nearest_fcurve_vert (bAnimContext *ac, const int mval[2]) 01073 { 01074 ListBase matches = {NULL, NULL}; 01075 tNearestVertInfo *nvi; 01076 01077 /* step 1: get the nearest verts */ 01078 get_nearest_fcurve_verts_list(ac, mval, &matches); 01079 01080 /* step 2: find the best vert */ 01081 nvi= get_best_nearest_fcurve_vert(&matches); 01082 01083 BLI_freelistN(&matches); 01084 01085 /* return the best vert found */ 01086 return nvi; 01087 } 01088 01089 /* ------------------- */ 01090 01091 /* option 1) select keyframe directly under mouse */ 01092 static void mouse_graph_keys (bAnimContext *ac, const int mval[2], short select_mode, short curves_only) 01093 { 01094 SpaceIpo *sipo= (SpaceIpo *)ac->sa->spacedata.first; 01095 tNearestVertInfo *nvi; 01096 BezTriple *bezt= NULL; 01097 01098 /* find the beztriple that we're selecting, and the handle that was clicked on */ 01099 nvi = find_nearest_fcurve_vert(ac, mval); 01100 01101 /* check if anything to select */ 01102 if (nvi == NULL) 01103 return; 01104 01105 /* deselect all other curves? */ 01106 if (select_mode == SELECT_REPLACE) { 01107 /* reset selection mode */ 01108 select_mode= SELECT_ADD; 01109 01110 /* deselect all other keyframes */ 01111 deselect_graph_keys(ac, 0, SELECT_SUBTRACT); 01112 01113 /* deselect other channels too, but only only do this if 01114 * selection of channel when the visibility of keyframes 01115 * doesn't depend on this 01116 */ 01117 if ((sipo->flag & SIPO_SELCUVERTSONLY) == 0) 01118 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); 01119 } 01120 01121 /* if points can be selected on this F-Curve */ 01122 // TODO: what about those with no keyframes? 01123 if ((curves_only == 0) && ((nvi->fcu->flag & FCURVE_PROTECTED)==0)) { 01124 /* only if there's keyframe */ 01125 if (nvi->bezt) { 01126 bezt= nvi->bezt; /* used to check bezt seletion is set */ 01127 /* depends on selection mode */ 01128 if (select_mode == SELECT_INVERT) { 01129 /* keyframe - invert select of all */ 01130 if (nvi->hpoint == NEAREST_HANDLE_KEY) { 01131 if (BEZSELECTED(bezt)) { 01132 BEZ_DESEL(bezt); 01133 } 01134 else { 01135 BEZ_SEL(bezt); 01136 } 01137 } 01138 01139 /* handles - toggle selection of relevant handle */ 01140 else if (nvi->hpoint == NEAREST_HANDLE_LEFT) { 01141 /* toggle selection */ 01142 bezt->f1 ^= SELECT; 01143 } 01144 else { 01145 /* toggle selection */ 01146 bezt->f3 ^= SELECT; 01147 } 01148 } 01149 else { 01150 /* if the keyframe was clicked on, select all verts of given beztriple */ 01151 if (nvi->hpoint == NEAREST_HANDLE_KEY) { 01152 BEZ_SEL(bezt); 01153 } 01154 /* otherwise, select the handle that applied */ 01155 else if (nvi->hpoint == NEAREST_HANDLE_LEFT) 01156 bezt->f1 |= SELECT; 01157 else 01158 bezt->f3 |= SELECT; 01159 } 01160 } 01161 else if (nvi->fpt) { 01162 // TODO: need to handle sample points 01163 } 01164 } 01165 else { 01166 KeyframeEditFunc select_cb; 01167 KeyframeEditData ked; 01168 01169 /* initialise keyframe editing data */ 01170 memset(&ked, 0, sizeof(KeyframeEditData)); 01171 01172 /* set up BezTriple edit callbacks */ 01173 select_cb= ANIM_editkeyframes_select(select_mode); 01174 01175 /* select all keyframes */ 01176 ANIM_fcurve_keyframes_loop(&ked, nvi->fcu, NULL, select_cb, NULL); 01177 } 01178 01179 /* only change selection of channel when the visibility of keyframes doesn't depend on this */ 01180 if ((sipo->flag & SIPO_SELCUVERTSONLY) == 0) { 01181 /* select or deselect curve? */ 01182 if (bezt) { 01183 /* take selection status from item that got hit, to prevent flip/flop on channel 01184 * selection status when shift-selecting (i.e. "SELECT_INVERT") points 01185 */ 01186 if (BEZSELECTED(bezt)) 01187 nvi->fcu->flag |= FCURVE_SELECTED; 01188 else 01189 nvi->fcu->flag &= ~FCURVE_SELECTED; 01190 } 01191 else { 01192 /* didn't hit any channel, so just apply that selection mode to the curve's selection status */ 01193 if (select_mode == SELECT_INVERT) 01194 nvi->fcu->flag ^= FCURVE_SELECTED; 01195 else if (select_mode == SELECT_ADD) 01196 nvi->fcu->flag |= FCURVE_SELECTED; 01197 } 01198 } 01199 01200 /* set active F-Curve (NOTE: sync the filter flags with findnearest_fcurve_vert) */ 01201 /* needs to be called with (sipo->flag & SIPO_SELCUVERTSONLY) otherwise the active flag won't be set [#26452] */ 01202 if (nvi->fcu->flag & FCURVE_SELECTED) { 01203 int filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); 01204 ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nvi->fcu, ANIMTYPE_FCURVE); 01205 } 01206 01207 /* free temp sample data for filtering */ 01208 MEM_freeN(nvi); 01209 } 01210 01211 /* Option 2) Selects all the keyframes on either side of the current frame (depends on which side the mouse is on) */ 01212 /* (see graphkeys_select_leftright) */ 01213 01214 /* Option 3) Selects all visible keyframes in the same frame as the mouse click */ 01215 static void graphkeys_mselect_column (bAnimContext *ac, const int mval[2], short select_mode) 01216 { 01217 ListBase anim_data= {NULL, NULL}; 01218 bAnimListElem *ale; 01219 int filter; 01220 01221 SpaceIpo *sipo= (SpaceIpo *)ac->sa->spacedata.first; 01222 KeyframeEditFunc select_cb, ok_cb; 01223 KeyframeEditData ked; 01224 tNearestVertInfo *nvi; 01225 float selx = (float)ac->scene->r.cfra; 01226 01227 /* find the beztriple that we're selecting, and the handle that was clicked on */ 01228 nvi = find_nearest_fcurve_vert(ac, mval); 01229 01230 /* check if anything to select */ 01231 if (nvi == NULL) 01232 return; 01233 01234 /* get frame number on which elements should be selected */ 01235 // TODO: should we restrict to integer frames only? 01236 if (nvi->bezt) 01237 selx= nvi->bezt->vec[1][0]; 01238 else if (nvi->fpt) 01239 selx= nvi->fpt->vec[0]; 01240 01241 /* if select mode is replace, deselect all keyframes (and channels) first */ 01242 if (select_mode==SELECT_REPLACE) { 01243 /* reset selection mode to add to selection */ 01244 select_mode= SELECT_ADD; 01245 01246 /* deselect all other keyframes */ 01247 deselect_graph_keys(ac, 0, SELECT_SUBTRACT); 01248 01249 /* deselect other channels too, but only only do this if 01250 * selection of channel when the visibility of keyframes 01251 * doesn't depend on this 01252 */ 01253 if ((sipo->flag & SIPO_SELCUVERTSONLY) == 0) 01254 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); 01255 } 01256 01257 /* initialise keyframe editing data */ 01258 memset(&ked, 0, sizeof(KeyframeEditData)); 01259 01260 /* set up BezTriple edit callbacks */ 01261 select_cb= ANIM_editkeyframes_select(select_mode); 01262 ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME); 01263 01264 /* loop through all of the keys and select additional keyframes 01265 * based on the keys found to be selected above 01266 */ 01267 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); 01268 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 01269 01270 for (ale= anim_data.first; ale; ale= ale->next) { 01271 AnimData *adt= ANIM_nla_mapping_get(ac, ale); 01272 01273 /* set frame for validation callback to refer to */ 01274 if (adt) 01275 ked.f1= BKE_nla_tweakedit_remap(adt, selx, NLATIME_CONVERT_UNMAP); 01276 else 01277 ked.f1= selx; 01278 01279 /* select elements with frame number matching cfra */ 01280 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); 01281 } 01282 01283 /* free elements */ 01284 MEM_freeN(nvi); 01285 BLI_freelistN(&ked.list); 01286 BLI_freelistN(&anim_data); 01287 } 01288 01289 /* ------------------- */ 01290 01291 /* handle clicking */ 01292 static int graphkeys_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *event) 01293 { 01294 bAnimContext ac; 01295 short selectmode; 01296 01297 /* get editor data */ 01298 if (ANIM_animdata_get_context(C, &ac) == 0) 01299 return OPERATOR_CANCELLED; 01300 01301 /* select mode is either replace (deselect all, then add) or add/extend */ 01302 if (RNA_boolean_get(op->ptr, "extend")) 01303 selectmode= SELECT_INVERT; 01304 else 01305 selectmode= SELECT_REPLACE; 01306 01307 /* figure out action to take */ 01308 if (RNA_boolean_get(op->ptr, "column")) { 01309 /* select all keyframes in the same frame as the one that was under the mouse */ 01310 graphkeys_mselect_column(&ac, event->mval, selectmode); 01311 } 01312 else if (RNA_boolean_get(op->ptr, "curves")) { 01313 /* select all keyframes in the same F-Curve as the one under the mouse */ 01314 mouse_graph_keys(&ac, event->mval, selectmode, 1); 01315 } 01316 else { 01317 /* select keyframe under mouse */ 01318 mouse_graph_keys(&ac, event->mval, selectmode, 0); 01319 } 01320 01321 /* set notifier that keyframe selection (and also channel selection in some cases) has changed */ 01322 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|ND_ANIMCHAN|NA_SELECTED, NULL); 01323 01324 /* for tweak grab to work */ 01325 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH; 01326 } 01327 01328 void GRAPH_OT_clickselect (wmOperatorType *ot) 01329 { 01330 /* identifiers */ 01331 ot->name= "Mouse Select Keys"; 01332 ot->idname= "GRAPH_OT_clickselect"; 01333 ot->description= "Select keyframes by clicking on them"; 01334 01335 /* api callbacks */ 01336 ot->invoke= graphkeys_clickselect_invoke; 01337 ot->poll= graphop_visible_keyframes_poll; 01338 01339 /* id-props */ 01340 RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY 01341 RNA_def_boolean(ot->srna, "column", 0, "Column Select", "Select all keyframes that occur on the same frame as the one under the mouse"); // ALTKEY 01342 RNA_def_boolean(ot->srna, "curves", 0, "Only Curves", "Select all the keyframes in the curve"); // CTRLKEY + ALTKEY 01343 } 01344 01345 /* ************************************************************************** */