|
Blender
V2.59
|
00001 /* 00002 * $Id: action_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_dlrbTree.h" 00042 #include "BLI_utildefines.h" 00043 00044 #include "DNA_anim_types.h" 00045 #include "DNA_gpencil_types.h" 00046 #include "DNA_object_types.h" 00047 #include "DNA_scene_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_gpencil.h" 00060 #include "ED_keyframes_draw.h" 00061 #include "ED_keyframes_edit.h" 00062 #include "ED_markers.h" 00063 #include "ED_screen.h" 00064 00065 #include "WM_api.h" 00066 #include "WM_types.h" 00067 00068 #include "action_intern.h" 00069 00070 00071 /* ************************************************************************** */ 00072 /* KEYFRAMES STUFF */ 00073 00074 /* ******************** Deselect All Operator ***************************** */ 00075 /* This operator works in one of three ways: 00076 * 1) (de)select all (AKEY) - test if select all or deselect all 00077 * 2) invert all (CTRL-IKEY) - invert selection of all keyframes 00078 * 3) (de)select all - no testing is done; only for use internal tools as normal function... 00079 */ 00080 00081 /* Deselects keyframes in the action editor 00082 * - This is called by the deselect all operator, as well as other ones! 00083 * 00084 * - test: check if select or deselect all 00085 * - sel: how to select keyframes (SELECT_*) 00086 */ 00087 static void deselect_action_keys (bAnimContext *ac, short test, short sel) 00088 { 00089 ListBase anim_data = {NULL, NULL}; 00090 bAnimListElem *ale; 00091 int filter; 00092 00093 KeyframeEditData ked= {{NULL}}; 00094 KeyframeEditFunc test_cb, sel_cb; 00095 00096 /* determine type-based settings */ 00097 if (ac->datatype == ANIMCONT_GPENCIL) 00098 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NODUPLIS); 00099 else 00100 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); 00101 00102 /* filter data */ 00103 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00104 00105 /* init BezTriple looping data */ 00106 test_cb= ANIM_editkeyframes_ok(BEZT_OK_SELECTED); 00107 00108 /* See if we should be selecting or deselecting */ 00109 if (test) { 00110 for (ale= anim_data.first; ale; ale= ale->next) { 00111 if (ale->type == ANIMTYPE_GPLAYER) { 00112 if (is_gplayer_frame_selected(ale->data)) { 00113 sel= SELECT_SUBTRACT; 00114 break; 00115 } 00116 } 00117 else { 00118 if (ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, test_cb, NULL)) { 00119 sel= SELECT_SUBTRACT; 00120 break; 00121 } 00122 } 00123 } 00124 } 00125 00126 /* convert sel to selectmode, and use that to get editor */ 00127 sel_cb= ANIM_editkeyframes_select(sel); 00128 00129 /* Now set the flags */ 00130 for (ale= anim_data.first; ale; ale= ale->next) { 00131 if (ale->type == ANIMTYPE_GPLAYER) 00132 set_gplayer_frame_selection(ale->data, sel); 00133 else 00134 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, sel_cb, NULL); 00135 } 00136 00137 /* Cleanup */ 00138 BLI_freelistN(&anim_data); 00139 } 00140 00141 /* ------------------- */ 00142 00143 static int actkeys_deselectall_exec(bContext *C, wmOperator *op) 00144 { 00145 bAnimContext ac; 00146 00147 /* get editor data */ 00148 if (ANIM_animdata_get_context(C, &ac) == 0) 00149 return OPERATOR_CANCELLED; 00150 00151 /* 'standard' behaviour - check if selected, then apply relevant selection */ 00152 if (RNA_boolean_get(op->ptr, "invert")) 00153 deselect_action_keys(&ac, 0, SELECT_INVERT); 00154 else 00155 deselect_action_keys(&ac, 1, SELECT_ADD); 00156 00157 /* set notifier that keyframe selection have changed */ 00158 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_SELECTED, NULL); 00159 00160 return OPERATOR_FINISHED; 00161 } 00162 00163 void ACTION_OT_select_all_toggle (wmOperatorType *ot) 00164 { 00165 /* identifiers */ 00166 ot->name= "Select All"; 00167 ot->idname= "ACTION_OT_select_all_toggle"; 00168 ot->description= "Toggle selection of all keyframes"; 00169 00170 /* api callbacks */ 00171 ot->exec= actkeys_deselectall_exec; 00172 ot->poll= ED_operator_action_active; 00173 00174 /* flags */ 00175 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00176 00177 /* props */ 00178 ot->prop= RNA_def_boolean(ot->srna, "invert", 0, "Invert", ""); 00179 } 00180 00181 /* ******************** Border Select Operator **************************** */ 00182 /* This operator currently works in one of three ways: 00183 * -> BKEY - 1) all keyframes within region are selected (ACTKEYS_BORDERSEL_ALLKEYS) 00184 * -> ALT-BKEY - depending on which axis of the region was larger... 00185 * -> 2) x-axis, so select all frames within frame range (ACTKEYS_BORDERSEL_FRAMERANGE) 00186 * -> 3) y-axis, so select all frames within channels that region included (ACTKEYS_BORDERSEL_CHANNELS) 00187 */ 00188 00189 /* defines for borderselect mode */ 00190 enum { 00191 ACTKEYS_BORDERSEL_ALLKEYS = 0, 00192 ACTKEYS_BORDERSEL_FRAMERANGE, 00193 ACTKEYS_BORDERSEL_CHANNELS, 00194 } /*eActKeys_BorderSelect_Mode*/; 00195 00196 00197 static void borderselect_action (bAnimContext *ac, rcti rect, short mode, short selectmode) 00198 { 00199 ListBase anim_data = {NULL, NULL}; 00200 bAnimListElem *ale; 00201 int filter, filterflag; 00202 00203 KeyframeEditData ked; 00204 KeyframeEditFunc ok_cb, select_cb; 00205 View2D *v2d= &ac->ar->v2d; 00206 rctf rectf; 00207 float ymin=0, ymax=(float)(-ACHANNEL_HEIGHT_HALF); 00208 00209 /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */ 00210 UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin+2, &rectf.xmin, &rectf.ymin); 00211 UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax-2, &rectf.xmax, &rectf.ymax); 00212 00213 /* filter data */ 00214 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS | ANIMFILTER_NODUPLIS); 00215 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00216 00217 /* get filtering flag for dopesheet data (if applicable) */ 00218 if (ac->datatype == ANIMCONT_DOPESHEET) { 00219 bDopeSheet *ads= (bDopeSheet *)ac->data; 00220 filterflag= ads->filterflag; 00221 } 00222 else 00223 filterflag= 0; 00224 00225 /* get beztriple editing/validation funcs */ 00226 select_cb= ANIM_editkeyframes_select(selectmode); 00227 00228 if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) 00229 ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); 00230 else 00231 ok_cb= NULL; 00232 00233 /* init editing data */ 00234 memset(&ked, 0, sizeof(KeyframeEditData)); 00235 00236 /* loop over data, doing border select */ 00237 for (ale= anim_data.first; ale; ale= ale->next) { 00238 AnimData *adt= ANIM_nla_mapping_get(ac, ale); 00239 00240 /* get new vertical minimum extent of channel */ 00241 ymin= ymax - ACHANNEL_STEP; 00242 00243 /* set horizontal range (if applicable) */ 00244 if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) { 00245 /* if channel is mapped in NLA, apply correction */ 00246 if (adt) { 00247 ked.f1= BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP); 00248 ked.f2= BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP); 00249 } 00250 else { 00251 ked.f1= rectf.xmin; 00252 ked.f2= rectf.xmax; 00253 } 00254 } 00255 00256 /* perform vertical suitability check (if applicable) */ 00257 if ( (mode == ACTKEYS_BORDERSEL_FRAMERANGE) || 00258 !((ymax < rectf.ymin) || (ymin > rectf.ymax)) ) 00259 { 00260 /* loop over data selecting */ 00261 if (ale->type == ANIMTYPE_GPLAYER) 00262 borderselect_gplayer_frames(ale->data, rectf.xmin, rectf.xmax, selectmode); 00263 else 00264 ANIM_animchannel_keyframes_loop(&ked, ale, ok_cb, select_cb, NULL, filterflag); 00265 } 00266 00267 /* set minimum extent to be the maximum of the next channel */ 00268 ymax=ymin; 00269 } 00270 00271 /* cleanup */ 00272 BLI_freelistN(&anim_data); 00273 } 00274 00275 /* ------------------- */ 00276 00277 static int actkeys_borderselect_exec(bContext *C, wmOperator *op) 00278 { 00279 bAnimContext ac; 00280 rcti rect; 00281 short mode=0, selectmode=0; 00282 int gesture_mode; 00283 00284 /* get editor data */ 00285 if (ANIM_animdata_get_context(C, &ac) == 0) 00286 return OPERATOR_CANCELLED; 00287 00288 /* get settings from operator */ 00289 rect.xmin= RNA_int_get(op->ptr, "xmin"); 00290 rect.ymin= RNA_int_get(op->ptr, "ymin"); 00291 rect.xmax= RNA_int_get(op->ptr, "xmax"); 00292 rect.ymax= RNA_int_get(op->ptr, "ymax"); 00293 00294 gesture_mode= RNA_int_get(op->ptr, "gesture_mode"); 00295 if (gesture_mode == GESTURE_MODAL_SELECT) 00296 selectmode = SELECT_ADD; 00297 else 00298 selectmode = SELECT_SUBTRACT; 00299 00300 /* selection 'mode' depends on whether borderselect region only matters on one axis */ 00301 if (RNA_boolean_get(op->ptr, "axis_range")) { 00302 /* mode depends on which axis of the range is larger to determine which axis to use 00303 * - checking this in region-space is fine, as it's fundamentally still going to be a different rect size 00304 * - the frame-range select option is favoured over the channel one (x over y), as frame-range one is often 00305 * used for tweaking timing when "blocking", while channels is not that useful... 00306 */ 00307 if ((rect.xmax - rect.xmin) >= (rect.ymax - rect.ymin)) 00308 mode= ACTKEYS_BORDERSEL_FRAMERANGE; 00309 else 00310 mode= ACTKEYS_BORDERSEL_CHANNELS; 00311 } 00312 else 00313 mode= ACTKEYS_BORDERSEL_ALLKEYS; 00314 00315 /* apply borderselect action */ 00316 borderselect_action(&ac, rect, mode, selectmode); 00317 00318 /* set notifier that keyframe selection have changed */ 00319 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_SELECTED, NULL); 00320 00321 return OPERATOR_FINISHED; 00322 } 00323 00324 void ACTION_OT_select_border(wmOperatorType *ot) 00325 { 00326 /* identifiers */ 00327 ot->name= "Border Select"; 00328 ot->idname= "ACTION_OT_select_border"; 00329 ot->description= "Select all keyframes within the specified region"; 00330 00331 /* api callbacks */ 00332 ot->invoke= WM_border_select_invoke; 00333 ot->exec= actkeys_borderselect_exec; 00334 ot->modal= WM_border_select_modal; 00335 ot->cancel= WM_border_select_cancel; 00336 00337 ot->poll= ED_operator_action_active; 00338 00339 /* flags */ 00340 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00341 00342 /* rna */ 00343 WM_operator_properties_gesture_border(ot, FALSE); 00344 00345 ot->prop= RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", ""); 00346 } 00347 00348 /* ******************** Column Select Operator **************************** */ 00349 /* This operator works in one of four ways: 00350 * - 1) select all keyframes in the same frame as a selected one (KKEY) 00351 * - 2) select all keyframes in the same frame as the current frame marker (CTRL-KKEY) 00352 * - 3) select all keyframes in the same frame as a selected markers (SHIFT-KKEY) 00353 * - 4) select all keyframes that occur between selected markers (ALT-KKEY) 00354 */ 00355 00356 /* defines for column-select mode */ 00357 static EnumPropertyItem prop_column_select_types[] = { 00358 {ACTKEYS_COLUMNSEL_KEYS, "KEYS", 0, "On Selected Keyframes", ""}, 00359 {ACTKEYS_COLUMNSEL_CFRA, "CFRA", 0, "On Current Frame", ""}, 00360 {ACTKEYS_COLUMNSEL_MARKERS_COLUMN, "MARKERS_COLUMN", 0, "On Selected Markers", ""}, 00361 {ACTKEYS_COLUMNSEL_MARKERS_BETWEEN, "MARKERS_BETWEEN", 0, "Between Min/Max Selected Markers", ""}, 00362 {0, NULL, 0, NULL, NULL} 00363 }; 00364 00365 /* ------------------- */ 00366 00367 /* Selects all visible keyframes between the specified markers */ 00368 static void markers_selectkeys_between (bAnimContext *ac) 00369 { 00370 ListBase anim_data = {NULL, NULL}; 00371 bAnimListElem *ale; 00372 int filter; 00373 00374 KeyframeEditFunc ok_cb, select_cb; 00375 KeyframeEditData ked= {{NULL}}; 00376 float min, max; 00377 00378 /* get extreme markers */ 00379 ED_markers_get_minmax(ac->markers, 1, &min, &max); 00380 min -= 0.5f; 00381 max += 0.5f; 00382 00383 /* get editing funcs + data */ 00384 ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); 00385 select_cb= ANIM_editkeyframes_select(SELECT_ADD); 00386 00387 ked.f1= min; 00388 ked.f2= max; 00389 00390 /* filter data */ 00391 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); 00392 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00393 00394 /* select keys in-between */ 00395 for (ale= anim_data.first; ale; ale= ale->next) { 00396 AnimData *adt= ANIM_nla_mapping_get(ac, ale); 00397 00398 if (adt) { 00399 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 00400 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); 00401 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); 00402 } 00403 else if (ale->type == ANIMTYPE_GPLAYER) { 00404 borderselect_gplayer_frames(ale->data, min, max, SELECT_ADD); 00405 } 00406 else { 00407 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); 00408 } 00409 } 00410 00411 /* Cleanup */ 00412 BLI_freelistN(&anim_data); 00413 } 00414 00415 00416 /* Selects all visible keyframes in the same frames as the specified elements */ 00417 static void columnselect_action_keys (bAnimContext *ac, short mode) 00418 { 00419 ListBase anim_data= {NULL, NULL}; 00420 bAnimListElem *ale; 00421 int filter; 00422 00423 Scene *scene= ac->scene; 00424 CfraElem *ce; 00425 KeyframeEditFunc select_cb, ok_cb; 00426 KeyframeEditData ked= {{NULL}}; 00427 00428 /* initialise keyframe editing data */ 00429 00430 /* build list of columns */ 00431 switch (mode) { 00432 case ACTKEYS_COLUMNSEL_KEYS: /* list of selected keys */ 00433 if (ac->datatype == ANIMCONT_GPENCIL) { 00434 filter= (ANIMFILTER_VISIBLE); 00435 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00436 00437 for (ale= anim_data.first; ale; ale= ale->next) 00438 gplayer_make_cfra_list(ale->data, &ked.list, 1); 00439 } 00440 else { 00441 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY); 00442 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00443 00444 for (ale= anim_data.first; ale; ale= ale->next) 00445 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_to_cfraelem, NULL); 00446 } 00447 BLI_freelistN(&anim_data); 00448 break; 00449 00450 case ACTKEYS_COLUMNSEL_CFRA: /* current frame */ 00451 /* make a single CfraElem for storing this */ 00452 ce= MEM_callocN(sizeof(CfraElem), "cfraElem"); 00453 BLI_addtail(&ked.list, ce); 00454 00455 ce->cfra= (float)CFRA; 00456 break; 00457 00458 case ACTKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */ 00459 ED_markers_make_cfra_list(ac->markers, &ked.list, SELECT); 00460 break; 00461 00462 default: /* invalid option */ 00463 return; 00464 } 00465 00466 /* set up BezTriple edit callbacks */ 00467 select_cb= ANIM_editkeyframes_select(SELECT_ADD); 00468 ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME); 00469 00470 /* loop through all of the keys and select additional keyframes 00471 * based on the keys found to be selected above 00472 */ 00473 if (ac->datatype == ANIMCONT_GPENCIL) 00474 filter= (ANIMFILTER_VISIBLE); 00475 else 00476 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY); 00477 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00478 00479 for (ale= anim_data.first; ale; ale= ale->next) { 00480 AnimData *adt= ANIM_nla_mapping_get(ac, ale); 00481 00482 /* loop over cfraelems (stored in the KeyframeEditData->list) 00483 * - we need to do this here, as we can apply fewer NLA-mapping conversions 00484 */ 00485 for (ce= ked.list.first; ce; ce= ce->next) { 00486 /* set frame for validation callback to refer to */ 00487 if (adt) 00488 ked.f1= BKE_nla_tweakedit_remap(adt, ce->cfra, NLATIME_CONVERT_UNMAP); 00489 else 00490 ked.f1= ce->cfra; 00491 00492 /* select elements with frame number matching cfraelem */ 00493 if (ale->type == ANIMTYPE_GPLAYER) 00494 select_gpencil_frame(ale->data, ce->cfra, SELECT_ADD); 00495 else 00496 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); 00497 } 00498 } 00499 00500 /* free elements */ 00501 BLI_freelistN(&ked.list); 00502 BLI_freelistN(&anim_data); 00503 } 00504 00505 /* ------------------- */ 00506 00507 static int actkeys_columnselect_exec(bContext *C, wmOperator *op) 00508 { 00509 bAnimContext ac; 00510 short mode; 00511 00512 /* get editor data */ 00513 if (ANIM_animdata_get_context(C, &ac) == 0) 00514 return OPERATOR_CANCELLED; 00515 00516 /* action to take depends on the mode */ 00517 mode= RNA_enum_get(op->ptr, "mode"); 00518 00519 if (mode == ACTKEYS_COLUMNSEL_MARKERS_BETWEEN) 00520 markers_selectkeys_between(&ac); 00521 else 00522 columnselect_action_keys(&ac, mode); 00523 00524 /* set notifier that keyframe selection have changed */ 00525 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_SELECTED, NULL); 00526 00527 return OPERATOR_FINISHED; 00528 } 00529 00530 void ACTION_OT_select_column (wmOperatorType *ot) 00531 { 00532 /* identifiers */ 00533 ot->name= "Select All"; 00534 ot->idname= "ACTION_OT_select_column"; 00535 ot->description= "Select all keyframes on the specified frame(s)"; 00536 00537 /* api callbacks */ 00538 ot->exec= actkeys_columnselect_exec; 00539 ot->poll= ED_operator_action_active; 00540 00541 /* flags */ 00542 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00543 00544 /* props */ 00545 ot->prop= RNA_def_enum(ot->srna, "mode", prop_column_select_types, 0, "Mode", ""); 00546 } 00547 00548 /* ******************** Select Linked Operator *********************** */ 00549 00550 static int actkeys_select_linked_exec (bContext *C, wmOperator *UNUSED(op)) 00551 { 00552 bAnimContext ac; 00553 00554 ListBase anim_data= {NULL, NULL}; 00555 bAnimListElem *ale; 00556 int filter; 00557 00558 KeyframeEditFunc ok_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED); 00559 KeyframeEditFunc sel_cb = ANIM_editkeyframes_select(SELECT_ADD); 00560 00561 /* get editor data */ 00562 if (ANIM_animdata_get_context(C, &ac) == 0) 00563 return OPERATOR_CANCELLED; 00564 00565 /* loop through all of the keys and select additional keyframes based on these */ 00566 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVEVISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); 00567 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); 00568 00569 for (ale= anim_data.first; ale; ale= ale->next) { 00570 FCurve *fcu= (FCurve *)ale->key_data; 00571 00572 /* check if anything selected? */ 00573 if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, ok_cb, NULL)) { 00574 /* select every keyframe in this curve then */ 00575 ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL); 00576 } 00577 } 00578 00579 /* Cleanup */ 00580 BLI_freelistN(&anim_data); 00581 00582 /* set notifier that keyframe selection has changed */ 00583 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_SELECTED, NULL); 00584 00585 return OPERATOR_FINISHED; 00586 } 00587 00588 void ACTION_OT_select_linked (wmOperatorType *ot) 00589 { 00590 /* identifiers */ 00591 ot->name = "Select Linked"; 00592 ot->idname= "ACTION_OT_select_linked"; 00593 ot->description = "Select keyframes occurring the same F-Curves as selected ones"; 00594 00595 /* api callbacks */ 00596 ot->exec= actkeys_select_linked_exec; 00597 ot->poll= ED_operator_action_active; 00598 00599 /* flags */ 00600 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; 00601 } 00602 00603 /* ******************** Select More/Less Operators *********************** */ 00604 00605 /* Common code to perform selection */ 00606 static void select_moreless_action_keys (bAnimContext *ac, short mode) 00607 { 00608 ListBase anim_data= {NULL, NULL}; 00609 bAnimListElem *ale; 00610 int filter; 00611 00612 KeyframeEditData ked= {{NULL}}; 00613 KeyframeEditFunc build_cb; 00614 00615 00616 /* init selmap building data */ 00617 build_cb= ANIM_editkeyframes_buildselmap(mode); 00618 00619 /* loop through all of the keys and select additional keyframes based on these */ 00620 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); 00621 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00622 00623 for (ale= anim_data.first; ale; ale= ale->next) { 00624 FCurve *fcu= (FCurve *)ale->key_data; 00625 00626 /* only continue if F-Curve has keyframes */ 00627 if (fcu->bezt == NULL) 00628 continue; 00629 00630 /* build up map of whether F-Curve's keyframes should be selected or not */ 00631 ked.data= MEM_callocN(fcu->totvert, "selmap actEdit more"); 00632 ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, build_cb, NULL); 00633 00634 /* based on this map, adjust the selection status of the keyframes */ 00635 ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, bezt_selmap_flush, NULL); 00636 00637 /* free the selmap used here */ 00638 MEM_freeN(ked.data); 00639 ked.data= NULL; 00640 } 00641 00642 /* Cleanup */ 00643 BLI_freelistN(&anim_data); 00644 } 00645 00646 /* ----------------- */ 00647 00648 static int actkeys_select_more_exec (bContext *C, wmOperator *UNUSED(op)) 00649 { 00650 bAnimContext ac; 00651 00652 /* get editor data */ 00653 if (ANIM_animdata_get_context(C, &ac) == 0) 00654 return OPERATOR_CANCELLED; 00655 00656 /* perform select changes */ 00657 select_moreless_action_keys(&ac, SELMAP_MORE); 00658 00659 /* set notifier that keyframe selection has changed */ 00660 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_SELECTED, NULL); 00661 00662 return OPERATOR_FINISHED; 00663 } 00664 00665 void ACTION_OT_select_more (wmOperatorType *ot) 00666 { 00667 /* identifiers */ 00668 ot->name = "Select More"; 00669 ot->idname= "ACTION_OT_select_more"; 00670 ot->description = "Select keyframes beside already selected ones"; 00671 00672 /* api callbacks */ 00673 ot->exec= actkeys_select_more_exec; 00674 ot->poll= ED_operator_action_active; 00675 00676 /* flags */ 00677 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; 00678 } 00679 00680 /* ----------------- */ 00681 00682 static int actkeys_select_less_exec (bContext *C, wmOperator *UNUSED(op)) 00683 { 00684 bAnimContext ac; 00685 00686 /* get editor data */ 00687 if (ANIM_animdata_get_context(C, &ac) == 0) 00688 return OPERATOR_CANCELLED; 00689 00690 /* perform select changes */ 00691 select_moreless_action_keys(&ac, SELMAP_LESS); 00692 00693 /* set notifier that keyframe selection has changed */ 00694 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|NA_SELECTED, NULL); 00695 00696 return OPERATOR_FINISHED; 00697 } 00698 00699 void ACTION_OT_select_less (wmOperatorType *ot) 00700 { 00701 /* identifiers */ 00702 ot->name = "Select Less"; 00703 ot->idname= "ACTION_OT_select_less"; 00704 ot->description = "Deselect keyframes on ends of selection islands"; 00705 00706 /* api callbacks */ 00707 ot->exec= actkeys_select_less_exec; 00708 ot->poll= ED_operator_action_active; 00709 00710 /* flags */ 00711 ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/; 00712 } 00713 00714 /* ******************** Select Left/Right Operator ************************* */ 00715 /* Select keyframes left/right of the current frame indicator */ 00716 00717 /* defines for left-right select tool */ 00718 static EnumPropertyItem prop_actkeys_leftright_select_types[] = { 00719 {ACTKEYS_LRSEL_TEST, "CHECK", 0, "Check if Select Left or Right", ""}, 00720 {ACTKEYS_LRSEL_LEFT, "LEFT", 0, "Before current frame", ""}, 00721 {ACTKEYS_LRSEL_RIGHT, "RIGHT", 0, "After current frame", ""}, 00722 {0, NULL, 0, NULL, NULL} 00723 }; 00724 00725 /* --------------------------------- */ 00726 00727 static void actkeys_select_leftright (bAnimContext *ac, short leftright, short select_mode) 00728 { 00729 ListBase anim_data = {NULL, NULL}; 00730 bAnimListElem *ale; 00731 int filter; 00732 00733 KeyframeEditFunc ok_cb, select_cb; 00734 KeyframeEditData ked= {{NULL}}; 00735 Scene *scene= ac->scene; 00736 00737 /* if select mode is replace, deselect all keyframes (and channels) first */ 00738 if (select_mode==SELECT_REPLACE) { 00739 select_mode= SELECT_ADD; 00740 00741 /* deselect all other channels and keyframes */ 00742 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); 00743 deselect_action_keys(ac, 0, SELECT_SUBTRACT); 00744 } 00745 00746 /* set callbacks and editing data */ 00747 ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE); 00748 select_cb= ANIM_editkeyframes_select(select_mode); 00749 00750 if (leftright == ACTKEYS_LRSEL_LEFT) { 00751 ked.f1 = MINAFRAMEF; 00752 ked.f2 = (float)(CFRA + 0.1f); 00753 } 00754 else { 00755 ked.f1 = (float)(CFRA - 0.1f); 00756 ked.f2 = MAXFRAMEF; 00757 } 00758 00759 /* filter data */ 00760 if (ac->datatype == ANIMCONT_GPENCIL) 00761 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NODUPLIS); 00762 else 00763 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); 00764 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00765 00766 /* select keys */ 00767 for (ale= anim_data.first; ale; ale= ale->next) { 00768 AnimData *adt= ANIM_nla_mapping_get(ac, ale); 00769 00770 if (adt) { 00771 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1); 00772 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); 00773 ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1); 00774 } 00775 else if (ale->type == ANIMTYPE_GPLAYER) 00776 borderselect_gplayer_frames(ale->data, ked.f1, ked.f2, select_mode); 00777 else 00778 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); 00779 } 00780 00781 /* Sync marker support */ 00782 if (select_mode==SELECT_ADD) { 00783 SpaceAction *saction= ac->sa->spacedata.first; 00784 00785 if ((saction) && (saction->flag & SACTION_MARKERS_MOVE)) { 00786 ListBase *markers = ED_animcontext_get_markers(ac); 00787 TimeMarker *marker; 00788 00789 for (marker= markers->first; marker; marker= marker->next) { 00790 if( ((leftright == ACTKEYS_LRSEL_LEFT) && (marker->frame < CFRA)) || 00791 ((leftright == ACTKEYS_LRSEL_RIGHT) && (marker->frame >= CFRA)) ) 00792 { 00793 marker->flag |= SELECT; 00794 } 00795 else { 00796 marker->flag &= ~SELECT; 00797 } 00798 } 00799 } 00800 } 00801 00802 /* Cleanup */ 00803 BLI_freelistN(&anim_data); 00804 } 00805 00806 /* ----------------- */ 00807 00808 static int actkeys_select_leftright_exec (bContext *C, wmOperator *op) 00809 { 00810 bAnimContext ac; 00811 short leftright = RNA_enum_get(op->ptr, "mode"); 00812 short selectmode; 00813 00814 /* get editor data */ 00815 if (ANIM_animdata_get_context(C, &ac) == 0) 00816 return OPERATOR_CANCELLED; 00817 00818 /* select mode is either replace (deselect all, then add) or add/extend */ 00819 if (RNA_boolean_get(op->ptr, "extend")) 00820 selectmode= SELECT_INVERT; 00821 else 00822 selectmode= SELECT_REPLACE; 00823 00824 /* if "test" mode is set, we don't have any info to set this with */ 00825 if (leftright == ACTKEYS_LRSEL_TEST) 00826 return OPERATOR_CANCELLED; 00827 00828 /* do the selecting now */ 00829 actkeys_select_leftright(&ac, leftright, selectmode); 00830 00831 /* set notifier that keyframe selection (and channels too) have changed */ 00832 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|ND_ANIMCHAN|NA_SELECTED, NULL); 00833 00834 return OPERATOR_FINISHED; 00835 } 00836 00837 static int actkeys_select_leftright_invoke (bContext *C, wmOperator *op, wmEvent *event) 00838 { 00839 bAnimContext ac; 00840 short leftright = RNA_enum_get(op->ptr, "mode"); 00841 00842 /* get editor data */ 00843 if (ANIM_animdata_get_context(C, &ac) == 0) 00844 return OPERATOR_CANCELLED; 00845 00846 /* handle mode-based testing */ 00847 if (leftright == ACTKEYS_LRSEL_TEST) { 00848 Scene *scene= ac.scene; 00849 ARegion *ar= ac.ar; 00850 View2D *v2d= &ar->v2d; 00851 float x; 00852 00853 /* determine which side of the current frame mouse is on */ 00854 UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, NULL); 00855 if (x < CFRA) 00856 RNA_enum_set(op->ptr, "mode", ACTKEYS_LRSEL_LEFT); 00857 else 00858 RNA_enum_set(op->ptr, "mode", ACTKEYS_LRSEL_RIGHT); 00859 } 00860 00861 /* perform selection */ 00862 return actkeys_select_leftright_exec(C, op); 00863 } 00864 00865 void ACTION_OT_select_leftright (wmOperatorType *ot) 00866 { 00867 /* identifiers */ 00868 ot->name= "Select Left/Right"; 00869 ot->idname= "ACTION_OT_select_leftright"; 00870 ot->description= "Select keyframes to the left or the right of the current frame"; 00871 00872 /* api callbacks */ 00873 ot->invoke= actkeys_select_leftright_invoke; 00874 ot->exec= actkeys_select_leftright_exec; 00875 ot->poll= ED_operator_action_active; 00876 00877 /* flags */ 00878 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 00879 00880 /* id-props */ 00881 ot->prop= RNA_def_enum(ot->srna, "mode", prop_actkeys_leftright_select_types, ACTKEYS_LRSEL_TEST, "Mode", ""); 00882 RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); 00883 } 00884 00885 /* ******************** Mouse-Click Select Operator *********************** */ 00886 /* This operator works in one of three ways: 00887 * - 1) keyframe under mouse - no special modifiers 00888 * - 2) all keyframes on the same side of current frame indicator as mouse - ALT modifier 00889 * - 3) column select all keyframes in frame under mouse - CTRL modifier 00890 * 00891 * In addition to these basic options, the SHIFT modifier can be used to toggle the 00892 * selection mode between replacing the selection (without) and inverting the selection (with). 00893 */ 00894 00895 /* sensitivity factor for frame-selections */ 00896 #define FRAME_CLICK_THRESH 0.1f 00897 00898 /* ------------------- */ 00899 00900 /* option 1) select keyframe directly under mouse */ 00901 static void actkeys_mselect_single (bAnimContext *ac, bAnimListElem *ale, short select_mode, float selx) 00902 { 00903 bDopeSheet *ads= (ac->datatype == ANIMCONT_DOPESHEET) ? ac->data : NULL; 00904 int ds_filter = ((ads) ? (ads->filterflag) : (0)); 00905 00906 KeyframeEditData ked= {{NULL}}; 00907 KeyframeEditFunc select_cb, ok_cb; 00908 00909 /* get functions for selecting keyframes */ 00910 select_cb= ANIM_editkeyframes_select(select_mode); 00911 ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME); 00912 ked.f1= selx; 00913 00914 /* select the nominated keyframe on the given frame */ 00915 if (ale->type == ANIMTYPE_GPLAYER) 00916 select_gpencil_frame(ale->data, selx, select_mode); 00917 else 00918 ANIM_animchannel_keyframes_loop(&ked, ale, ok_cb, select_cb, NULL, ds_filter); 00919 } 00920 00921 /* Option 2) Selects all the keyframes on either side of the current frame (depends on which side the mouse is on) */ 00922 /* (see actkeys_select_leftright) */ 00923 00924 /* Option 3) Selects all visible keyframes in the same frame as the mouse click */ 00925 static void actkeys_mselect_column(bAnimContext *ac, short select_mode, float selx) 00926 { 00927 ListBase anim_data= {NULL, NULL}; 00928 bAnimListElem *ale; 00929 int filter; 00930 00931 KeyframeEditFunc select_cb, ok_cb; 00932 KeyframeEditData ked= {{NULL}}; 00933 00934 /* initialise keyframe editing data */ 00935 00936 /* set up BezTriple edit callbacks */ 00937 select_cb= ANIM_editkeyframes_select(select_mode); 00938 ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME); 00939 00940 /* loop through all of the keys and select additional keyframes 00941 * based on the keys found to be selected above 00942 */ 00943 if (ac->datatype == ANIMCONT_GPENCIL) 00944 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_NODUPLIS); 00945 else 00946 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY | ANIMFILTER_NODUPLIS); 00947 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 00948 00949 for (ale= anim_data.first; ale; ale= ale->next) { 00950 AnimData *adt= ANIM_nla_mapping_get(ac, ale); 00951 00952 /* set frame for validation callback to refer to */ 00953 if (adt) 00954 ked.f1= BKE_nla_tweakedit_remap(adt, selx, NLATIME_CONVERT_UNMAP); 00955 else 00956 ked.f1= selx; 00957 00958 /* select elements with frame number matching cfra */ 00959 if (ale->type == ANIMTYPE_GPLAYER) 00960 select_gpencil_frame(ale->key_data, selx, select_mode); 00961 else 00962 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL); 00963 } 00964 00965 /* free elements */ 00966 BLI_freelistN(&ked.list); 00967 BLI_freelistN(&anim_data); 00968 } 00969 00970 /* ------------------- */ 00971 00972 static void mouse_action_keys (bAnimContext *ac, const int mval[2], short select_mode, short column) 00973 { 00974 ListBase anim_data = {NULL, NULL}; 00975 DLRBT_Tree anim_keys; 00976 bAnimListElem *ale; 00977 int filter; 00978 00979 View2D *v2d= &ac->ar->v2d; 00980 bDopeSheet *ads = NULL; 00981 int channel_index; 00982 short found = 0; 00983 float selx = 0.0f; 00984 float x, y; 00985 rctf rectf; 00986 00987 /* get dopesheet info */ 00988 if (ac->datatype == ANIMCONT_DOPESHEET) 00989 ads= ac->data; 00990 00991 /* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */ 00992 UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); 00993 UI_view2d_listview_view_to_cell(v2d, 0, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index); 00994 00995 /* x-range to check is +/- 7 (in screen/region-space) on either side of mouse click (size of keyframe icon) */ 00996 UI_view2d_region_to_view(v2d, mval[0]-7, mval[1], &rectf.xmin, &rectf.ymin); 00997 UI_view2d_region_to_view(v2d, mval[0]+7, mval[1], &rectf.xmax, &rectf.ymax); 00998 00999 /* filter data */ 01000 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS); 01001 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); 01002 01003 /* try to get channel */ 01004 ale= BLI_findlink(&anim_data, channel_index); 01005 if (ale == NULL) { 01006 /* channel not found */ 01007 printf("Error: animation channel (index = %d) not found in mouse_action_keys() \n", channel_index); 01008 BLI_freelistN(&anim_data); 01009 return; 01010 } 01011 else { 01012 /* found match - must return here... */ 01013 AnimData *adt= ANIM_nla_mapping_get(ac, ale); 01014 ActKeyColumn *ak, *akn=NULL; 01015 01016 /* make list of keyframes */ 01017 BLI_dlrbTree_init(&anim_keys); 01018 01019 if (ale->key_data) { 01020 switch (ale->datatype) { 01021 case ALE_SCE: 01022 { 01023 Scene *scene= (Scene *)ale->key_data; 01024 scene_to_keylist(ads, scene, &anim_keys, NULL); 01025 } 01026 break; 01027 case ALE_OB: 01028 { 01029 Object *ob= (Object *)ale->key_data; 01030 ob_to_keylist(ads, ob, &anim_keys, NULL); 01031 } 01032 break; 01033 case ALE_ACT: 01034 { 01035 bAction *act= (bAction *)ale->key_data; 01036 action_to_keylist(adt, act, &anim_keys, NULL); 01037 } 01038 break; 01039 case ALE_FCURVE: 01040 { 01041 FCurve *fcu= (FCurve *)ale->key_data; 01042 fcurve_to_keylist(adt, fcu, &anim_keys, NULL); 01043 } 01044 break; 01045 } 01046 } 01047 else if (ale->type == ANIMTYPE_SUMMARY) { 01048 /* dopesheet summary covers everything */ 01049 summary_to_keylist(ac, &anim_keys, NULL); 01050 } 01051 else if (ale->type == ANIMTYPE_GROUP) { 01052 // TODO: why don't we just give groups key_data too? 01053 bActionGroup *agrp= (bActionGroup *)ale->data; 01054 agroup_to_keylist(adt, agrp, &anim_keys, NULL); 01055 } 01056 else if (ale->type == ANIMTYPE_GPLAYER) { 01057 // TODO: why don't we just give gplayers key_data too? 01058 bGPDlayer *gpl = (bGPDlayer *)ale->data; 01059 gpl_to_keylist(ads, gpl, &anim_keys); 01060 } 01061 01062 /* start from keyframe at root of BST, traversing until we find one within the range that was clicked on */ 01063 for (ak= anim_keys.root; ak; ak= akn) { 01064 if (IN_RANGE(ak->cfra, rectf.xmin, rectf.xmax)) { 01065 /* set the frame to use, and apply inverse-correction for NLA-mapping 01066 * so that the frame will get selected by the selection functions without 01067 * requiring to map each frame once again... 01068 */ 01069 selx= BKE_nla_tweakedit_remap(adt, ak->cfra, NLATIME_CONVERT_UNMAP); 01070 found= 1; 01071 break; 01072 } 01073 else if (ak->cfra < rectf.xmin) 01074 akn= ak->right; 01075 else 01076 akn= ak->left; 01077 } 01078 01079 /* remove active channel from list of channels for separate treatment (since it's needed later on) */ 01080 BLI_remlink(&anim_data, ale); 01081 01082 /* cleanup temporary lists */ 01083 BLI_dlrbTree_free(&anim_keys); 01084 01085 /* free list of channels, since it's not used anymore */ 01086 BLI_freelistN(&anim_data); 01087 } 01088 01089 /* for replacing selection, firstly need to clear existing selection */ 01090 if (select_mode == SELECT_REPLACE) { 01091 /* reset selection mode for next steps */ 01092 select_mode = SELECT_ADD; 01093 01094 /* deselect all keyframes */ 01095 deselect_action_keys(ac, 0, SELECT_SUBTRACT); 01096 01097 /* highlight channel clicked on */ 01098 if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET)) { 01099 /* deselect all other channels first */ 01100 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); 01101 01102 /* Highlight Action-Group or F-Curve? */ 01103 if (ale && ale->data) { 01104 if (ale->type == ANIMTYPE_GROUP) { 01105 bActionGroup *agrp= ale->data; 01106 01107 agrp->flag |= AGRP_SELECTED; 01108 ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP); 01109 } 01110 else if (ale->type == ANIMTYPE_FCURVE) { 01111 FCurve *fcu= ale->data; 01112 01113 fcu->flag |= FCURVE_SELECTED; 01114 ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE); 01115 } 01116 } 01117 } 01118 else if (ac->datatype == ANIMCONT_GPENCIL) { 01119 /* deselect all other channels first */ 01120 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR); 01121 01122 /* Highlight GPencil Layer */ 01123 if ((ale && ale->data) && (ale->type == ANIMTYPE_GPLAYER)) { 01124 bGPDlayer *gpl = ale->data; 01125 01126 gpl->flag |= GP_LAYER_SELECT; 01127 //gpencil_layer_setactive(gpd, gpl); 01128 } 01129 } 01130 } 01131 01132 /* only select keyframes if we clicked on a valid channel and hit something */ 01133 if (ale) { 01134 if (found) { 01135 /* apply selection to keyframes */ 01136 if (column) { 01137 /* select all keyframes in the same frame as the one we hit on the active channel */ 01138 actkeys_mselect_column(ac, select_mode, selx); 01139 } 01140 else { 01141 /* select the nominated keyframe on the given frame */ 01142 actkeys_mselect_single(ac, ale, select_mode, selx); 01143 } 01144 } 01145 01146 /* free this channel */ 01147 MEM_freeN(ale); 01148 } 01149 } 01150 01151 /* handle clicking */ 01152 static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *event) 01153 { 01154 bAnimContext ac; 01155 ARegion *ar; 01156 short selectmode, column; 01157 01158 /* get editor data */ 01159 if (ANIM_animdata_get_context(C, &ac) == 0) 01160 return OPERATOR_CANCELLED; 01161 01162 /* get useful pointers from animation context data */ 01163 ar= ac.ar; 01164 01165 /* select mode is either replace (deselect all, then add) or add/extend */ 01166 if (RNA_boolean_get(op->ptr, "extend")) 01167 selectmode= SELECT_INVERT; 01168 else 01169 selectmode= SELECT_REPLACE; 01170 01171 /* column selection */ 01172 column= RNA_boolean_get(op->ptr, "column"); 01173 01174 /* select keyframe(s) based upon mouse position*/ 01175 mouse_action_keys(&ac, event->mval, selectmode, column); 01176 01177 /* set notifier that keyframe selection (and channels too) have changed */ 01178 WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|ND_ANIMCHAN|NA_SELECTED, NULL); 01179 01180 /* for tweak grab to work */ 01181 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH; 01182 } 01183 01184 void ACTION_OT_clickselect (wmOperatorType *ot) 01185 { 01186 /* identifiers */ 01187 ot->name= "Mouse Select Keys"; 01188 ot->idname= "ACTION_OT_clickselect"; 01189 ot->description= "Select keyframes by clicking on them"; 01190 01191 /* api callbacks - absolutely no exec() this yet... */ 01192 ot->invoke= actkeys_clickselect_invoke; 01193 ot->poll= ED_operator_action_active; 01194 01195 /* flags */ 01196 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; 01197 01198 /* id-props */ 01199 RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY 01200 RNA_def_boolean(ot->srna, "column", 0, "Column Select", ""); // ALTKEY 01201 } 01202 01203 /* ************************************************************************** */