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