Blender V2.61 - r43446

action_select.c

Go to the documentation of this file.
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 /* ************************************************************************** */