Blender  V2.59
action_select.c
Go to the documentation of this file.
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 /* ************************************************************************** */