Cleanup: spelling, indentation
[blender.git] / source / blender / editors / space_action / action_select.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation
19  *
20  * Contributor(s): Joshua Leung
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/editors/space_action/action_select.c
26  *  \ingroup spaction
27  */
28
29
30 #include <math.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <float.h>
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_blenlib.h"
38 #include "BLI_dlrbTree.h"
39 #include "BLI_lasso.h"
40 #include "BLI_utildefines.h"
41
42 #include "DNA_anim_types.h"
43 #include "DNA_gpencil_types.h"
44 #include "DNA_object_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_mask_types.h"
47
48 #include "RNA_access.h"
49 #include "RNA_define.h"
50
51 #include "BKE_fcurve.h"
52 #include "BKE_nla.h"
53 #include "BKE_context.h"
54
55 #include "UI_view2d.h"
56
57 #include "ED_anim_api.h"
58 #include "ED_gpencil.h"
59 #include "ED_mask.h"
60 #include "ED_keyframes_draw.h"
61 #include "ED_keyframes_edit.h"
62 #include "ED_markers.h"
63 #include "ED_screen.h"
64
65 #include "WM_api.h"
66 #include "WM_types.h"
67
68 #include "action_intern.h"
69
70
71 /* ************************************************************************** */
72 /* KEYFRAMES STUFF */
73
74 /* ******************** Deselect All Operator ***************************** */
75 /* This operator works in one of three ways:
76  *      1) (de)select all (AKEY) - test if select all or deselect all
77  *      2) invert all (CTRL-IKEY) - invert selection of all keyframes
78  *      3) (de)select all - no testing is done; only for use internal tools as normal function...
79  */
80
81 /* Deselects keyframes in the action editor
82  *      - This is called by the deselect all operator, as well as other ones!
83  *
84  *  - test: check if select or deselect all
85  *      - sel: how to select keyframes (SELECT_*)
86  */
87 static void deselect_action_keys(bAnimContext *ac, short test, short sel)
88 {
89         ListBase anim_data = {NULL, NULL};
90         bAnimListElem *ale;
91         int filter;
92         
93         KeyframeEditData ked = {{NULL}};
94         KeyframeEditFunc test_cb, sel_cb;
95         
96         /* determine type-based settings */
97         if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
98                 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
99         else
100                 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
101         
102         /* filter data */
103         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
104         
105         /* init BezTriple looping data */
106         test_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED);
107         
108         /* See if we should be selecting or deselecting */
109         if (test) {
110                 for (ale = anim_data.first; ale; ale = ale->next) {
111                         if (ale->type == ANIMTYPE_GPLAYER) {
112                                 if (ED_gplayer_frame_select_check(ale->data)) {
113                                         sel = SELECT_SUBTRACT;
114                                         break;
115                                 }
116                         }
117                         else if (ale->type == ANIMTYPE_MASKLAYER) {
118                                 if (ED_masklayer_frame_select_check(ale->data)) {
119                                         sel = SELECT_SUBTRACT;
120                                         break;
121                                 }
122                         }
123                         else {
124                                 if (ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, test_cb, NULL)) {
125                                         sel = SELECT_SUBTRACT;
126                                         break;
127                                 }
128                         }
129                 }
130         }
131         
132         /* convert sel to selectmode, and use that to get editor */
133         sel_cb = ANIM_editkeyframes_select(sel);
134         
135         /* Now set the flags */
136         for (ale = anim_data.first; ale; ale = ale->next) {
137                 if (ale->type == ANIMTYPE_GPLAYER)
138                         ED_gplayer_frame_select_set(ale->data, sel);
139                 else if (ale->type == ANIMTYPE_MASKLAYER)
140                         ED_masklayer_frame_select_set(ale->data, sel);
141                 else
142                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, sel_cb, NULL); 
143         }
144         
145         /* Cleanup */
146         ANIM_animdata_freelist(&anim_data);
147 }
148
149 /* ------------------- */
150
151 static int actkeys_deselectall_exec(bContext *C, wmOperator *op)
152 {
153         bAnimContext ac;
154         
155         /* get editor data */
156         if (ANIM_animdata_get_context(C, &ac) == 0)
157                 return OPERATOR_CANCELLED;
158                 
159         /* 'standard' behavior - check if selected, then apply relevant selection */
160         if (RNA_boolean_get(op->ptr, "invert"))
161                 deselect_action_keys(&ac, 0, SELECT_INVERT);
162         else
163                 deselect_action_keys(&ac, 1, SELECT_ADD);
164         
165         /* set notifier that keyframe selection have changed */
166         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
167         
168         return OPERATOR_FINISHED;
169 }
170  
171 void ACTION_OT_select_all_toggle(wmOperatorType *ot)
172 {
173         /* identifiers */
174         ot->name = "Select All";
175         ot->idname = "ACTION_OT_select_all_toggle";
176         ot->description = "Toggle selection of all keyframes";
177         
178         /* api callbacks */
179         ot->exec = actkeys_deselectall_exec;
180         ot->poll = ED_operator_action_active;
181         
182         /* flags */
183         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
184         
185         /* props */
186         ot->prop = RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
187         RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
188 }
189
190 /* ******************** Border Select Operator **************************** */
191 /* This operator currently works in one of three ways:
192  *      -> BKEY     - 1) all keyframes within region are selected (ACTKEYS_BORDERSEL_ALLKEYS)
193  *      -> ALT-BKEY - depending on which axis of the region was larger...
194  *              -> 2) x-axis, so select all frames within frame range (ACTKEYS_BORDERSEL_FRAMERANGE)
195  *              -> 3) y-axis, so select all frames within channels that region included (ACTKEYS_BORDERSEL_CHANNELS)
196  */
197
198 /* defines for borderselect mode */
199 enum {
200         ACTKEYS_BORDERSEL_ALLKEYS   = 0,
201         ACTKEYS_BORDERSEL_FRAMERANGE,
202         ACTKEYS_BORDERSEL_CHANNELS,
203 } /*eActKeys_BorderSelect_Mode*/;
204
205
206 static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, short selectmode)
207 {
208         ListBase anim_data = {NULL, NULL};
209         bAnimListElem *ale;
210         int filter;
211         
212         KeyframeEditData ked;
213         KeyframeEditFunc ok_cb, select_cb;
214         View2D *v2d = &ac->ar->v2d;
215         rctf rectf;
216         float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF);
217         
218         /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */
219         UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin + 2, &rectf.xmin, &rectf.ymin);
220         UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax - 2, &rectf.xmax, &rectf.ymax);
221         
222         /* filter data */
223         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
224         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
225         
226         /* get beztriple editing/validation funcs  */
227         select_cb = ANIM_editkeyframes_select(selectmode);
228         
229         if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS))
230                 ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
231         else
232                 ok_cb = NULL;
233                 
234         /* init editing data */
235         memset(&ked, 0, sizeof(KeyframeEditData));
236         
237         /* loop over data, doing border select */
238         for (ale = anim_data.first; ale; ale = ale->next) {
239                 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
240                 
241                 /* get new vertical minimum extent of channel */
242                 ymin = ymax - ACHANNEL_STEP;
243                 
244                 /* set horizontal range (if applicable) */
245                 if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) {
246                         /* if channel is mapped in NLA, apply correction */
247                         if (adt) {
248                                 ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP);
249                                 ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP);
250                                 ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP);
251                         }
252                         else {
253                                 ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */
254                                 ked.f1 = rectf.xmin;
255                                 ked.f2 = rectf.xmax;
256                         }
257                 }
258                 
259                 /* perform vertical suitability check (if applicable) */
260                 if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) ||
261                     !((ymax < rectf.ymin) || (ymin > rectf.ymax)))
262                 {
263                         /* loop over data selecting */
264                         switch (ale->type) {
265                                 case ANIMTYPE_GPDATABLOCK:
266                                 {
267                                         bGPdata *gpd = ale->data;
268                                         bGPDlayer *gpl;
269                                         for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
270                                                 ED_gplayer_frames_select_border(gpl, rectf.xmin, rectf.xmax, selectmode);
271                                         }
272                                         break;
273                                 }
274                                 case ANIMTYPE_GPLAYER:
275                                         ED_gplayer_frames_select_border(ale->data, rectf.xmin, rectf.xmax, selectmode);
276                                         break;
277                                 case ANIMTYPE_MASKDATABLOCK:
278                                 {
279                                         Mask *mask = ale->data;
280                                         MaskLayer *masklay;
281                                         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
282                                                 ED_masklayer_frames_select_border(masklay, rectf.xmin, rectf.xmax, selectmode);
283                                         }
284                                         break;
285                                 }
286                                 case ANIMTYPE_MASKLAYER:
287                                         ED_masklayer_frames_select_border(ale->data, rectf.xmin, rectf.xmax, selectmode);
288                                         break;
289                                 default:
290                                         ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL);
291                                         break;
292                         }
293                 }
294                 
295                 /* set minimum extent to be the maximum of the next channel */
296                 ymax = ymin;
297         }
298         
299         /* cleanup */
300         ANIM_animdata_freelist(&anim_data);
301 }
302
303 /* ------------------- */
304
305 static int actkeys_borderselect_exec(bContext *C, wmOperator *op)
306 {
307         bAnimContext ac;
308         rcti rect;
309         short mode = 0, selectmode = 0;
310         int gesture_mode;
311         bool extend;
312         
313         /* get editor data */
314         if (ANIM_animdata_get_context(C, &ac) == 0)
315                 return OPERATOR_CANCELLED;
316
317         /* clear all selection if not extending selection */
318         extend = RNA_boolean_get(op->ptr, "extend");
319         if (!extend)
320                 deselect_action_keys(&ac, 1, SELECT_SUBTRACT);
321         
322         /* get settings from operator */
323         WM_operator_properties_border_to_rcti(op, &rect);
324                 
325         gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
326         if (gesture_mode == GESTURE_MODAL_SELECT)
327                 selectmode = SELECT_ADD;
328         else
329                 selectmode = SELECT_SUBTRACT;
330         
331         /* selection 'mode' depends on whether borderselect region only matters on one axis */
332         if (RNA_boolean_get(op->ptr, "axis_range")) {
333                 /* mode depends on which axis of the range is larger to determine which axis to use 
334                  *      - checking this in region-space is fine, as it's fundamentally still going to be a different rect size
335                  *      - the frame-range select option is favored over the channel one (x over y), as frame-range one is often
336                  *        used for tweaking timing when "blocking", while channels is not that useful...
337                  */
338                 if (BLI_rcti_size_x(&rect) >= BLI_rcti_size_y(&rect))
339                         mode = ACTKEYS_BORDERSEL_FRAMERANGE;
340                 else
341                         mode = ACTKEYS_BORDERSEL_CHANNELS;
342         }
343         else 
344                 mode = ACTKEYS_BORDERSEL_ALLKEYS;
345         
346         /* apply borderselect action */
347         borderselect_action(&ac, rect, mode, selectmode);
348         
349         /* set notifier that keyframe selection have changed */
350         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
351         
352         return OPERATOR_FINISHED;
353
354
355 void ACTION_OT_select_border(wmOperatorType *ot)
356 {
357         /* identifiers */
358         ot->name = "Border Select";
359         ot->idname = "ACTION_OT_select_border";
360         ot->description = "Select all keyframes within the specified region";
361         
362         /* api callbacks */
363         ot->invoke = WM_border_select_invoke;
364         ot->exec = actkeys_borderselect_exec;
365         ot->modal = WM_border_select_modal;
366         ot->cancel = WM_border_select_cancel;
367         
368         ot->poll = ED_operator_action_active;
369         
370         /* flags */
371         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
372         
373         /* rna */
374         WM_operator_properties_gesture_border(ot, true);
375         
376         ot->prop = RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", "");
377 }
378
379 /* ******************** Region Select Operators ***************************** */
380 /* "Region Select" operators include the Lasso and Circle Select operators.
381  * These two ended up being lumped together, as it was easier in the 
382  * original Graph Editor implementation of these to do it this way.
383  */
384
385 static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, short mode, short selectmode, void *data)
386 {
387         ListBase anim_data = {NULL, NULL};
388         bAnimListElem *ale;
389         int filter;
390         
391         KeyframeEditData ked;
392         KeyframeEditFunc ok_cb, select_cb;
393         View2D *v2d = &ac->ar->v2d;
394         rctf rectf, scaled_rectf;
395         float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF);
396         
397         /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */
398         UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf);
399         
400         /* filter data */
401         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
402         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
403         
404         /* get beztriple editing/validation funcs  */
405         select_cb = ANIM_editkeyframes_select(selectmode);
406         ok_cb = ANIM_editkeyframes_ok(mode);
407         
408         /* init editing data */
409         memset(&ked, 0, sizeof(KeyframeEditData));
410         if (mode == BEZT_OK_CHANNEL_LASSO) {
411                 KeyframeEdit_LassoData *data_lasso = data;
412                 data_lasso->rectf_scaled = &scaled_rectf;
413                 ked.data = data_lasso;
414         }
415         else if (mode == BEZT_OK_CHANNEL_CIRCLE) {
416                 KeyframeEdit_CircleData *data_circle = data;
417                 data_circle->rectf_scaled = &scaled_rectf;
418                 ked.data = data;
419         }
420         else {
421                 ked.data = &scaled_rectf;
422         }
423         
424         /* loop over data, doing region select */
425         for (ale = anim_data.first; ale; ale = ale->next) {
426                 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
427                 
428                 /* get new vertical minimum extent of channel */
429                 ymin = ymax - ACHANNEL_STEP;
430                 
431                 /* compute midpoint of channel (used for testing if the key is in the region or not) */
432                 ked.channel_y = ymin + ACHANNEL_HEIGHT_HALF;
433                 
434                 /* if channel is mapped in NLA, apply correction
435                  * - Apply to the bounds being checked, not all the keyframe points,
436                  *   to avoid having scaling everything
437                  * - Save result to the scaled_rect, which is all that these operators
438                  *   will read from
439                  */
440                 if (adt) {
441                         ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP);
442                         ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP);
443                         ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP);
444                 }
445                 else {
446                         ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */
447                         ked.f1 = rectf.xmin;
448                         ked.f2 = rectf.xmax;
449                 }
450                 
451                 /* Update values for scaled_rectf - which is used to compute the mapping in the callbacks
452                  * NOTE: Since summary tracks need late-binding remapping, the callbacks may overwrite these 
453                  *       with the properly remapped ked.f1/f2 values, when needed
454                  */
455                 scaled_rectf.xmin = ked.f1;
456                 scaled_rectf.xmax = ked.f2;
457                 scaled_rectf.ymin = ymin;
458                 scaled_rectf.ymax = ymax;
459                 
460                 /* perform vertical suitability check (if applicable) */
461                 if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) ||
462                     !((ymax < rectf.ymin) || (ymin > rectf.ymax)))
463                 {
464                         /* loop over data selecting */
465                         switch (ale->type) {
466                                 case ANIMTYPE_GPDATABLOCK:
467                                 {
468                                         bGPdata *gpd = ale->data;
469                                         bGPDlayer *gpl;
470                                         for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
471                                                 ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode);
472                                         }
473                                         break;
474                                 }
475                                 case ANIMTYPE_GPLAYER:
476                                 {
477                                         ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode);
478                                         break;
479                                 }
480                                 case ANIMTYPE_MASKDATABLOCK:
481                                 {
482                                         Mask *mask = ale->data;
483                                         MaskLayer *masklay;
484                                         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
485                                                 ED_masklayer_frames_select_region(&ked, masklay, mode, selectmode);
486                                         }
487                                         break;
488                                 }
489                                 case ANIMTYPE_MASKLAYER:
490                                 {
491                                         ED_masklayer_frames_select_region(&ked, ale->data, mode, selectmode);
492                                         break;
493                                 }
494                                 default:
495                                         ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL);
496                                         break;
497                         }
498                 }
499                 
500                 /* set minimum extent to be the maximum of the next channel */
501                 ymax = ymin;
502         }
503         
504         /* cleanup */
505         ANIM_animdata_freelist(&anim_data);
506 }
507  
508 /* ----------------------------------- */
509  
510 static int actkeys_lassoselect_exec(bContext *C, wmOperator *op)
511 {
512         bAnimContext ac;
513         
514         KeyframeEdit_LassoData data_lasso;
515         rcti rect;
516         rctf rect_fl;
517         
518         short selectmode;
519         bool extend;
520         
521         /* get editor data */
522         if (ANIM_animdata_get_context(C, &ac) == 0)
523                 return OPERATOR_CANCELLED;
524         
525         data_lasso.rectf_view = &rect_fl;
526         data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot);
527         if (data_lasso.mcords == NULL)
528                 return OPERATOR_CANCELLED;
529         
530         /* clear all selection if not extending selection */
531         extend = RNA_boolean_get(op->ptr, "extend");
532         if (!extend)
533                 deselect_action_keys(&ac, 1, SELECT_SUBTRACT);
534         
535         if (!RNA_boolean_get(op->ptr, "deselect"))
536                 selectmode = SELECT_ADD;
537         else
538                 selectmode = SELECT_SUBTRACT;
539         
540         /* get settings from operator */
541         BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot);
542         BLI_rctf_rcti_copy(&rect_fl, &rect);
543         
544         /* apply borderselect action */
545         region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso);
546         
547         MEM_freeN((void *)data_lasso.mcords);
548         
549         /* send notifier that keyframe selection has changed */
550         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
551         
552         return OPERATOR_FINISHED;
553 }
554
555 void ACTION_OT_select_lasso(wmOperatorType *ot)
556 {
557         /* identifiers */
558         ot->name = "Lasso Select";
559         ot->description = "Select keyframe points using lasso selection";
560         ot->idname = "ACTION_OT_select_lasso";
561         
562         /* api callbacks */
563         ot->invoke = WM_gesture_lasso_invoke;
564         ot->modal = WM_gesture_lasso_modal;
565         ot->exec = actkeys_lassoselect_exec;
566         ot->poll = ED_operator_action_active;
567         ot->cancel = WM_gesture_lasso_cancel;
568         
569         /* flags */
570         ot->flag = OPTYPE_UNDO;
571         
572         /* properties */
573         RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
574         RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items");
575         RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
576 }
577
578 /* ------------------- */
579
580 static int action_circle_select_exec(bContext *C, wmOperator *op)
581 {
582         bAnimContext ac;
583         const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
584         const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT;
585         
586         KeyframeEdit_CircleData data = {0};
587         rctf rect_fl;
588         
589         float x = RNA_int_get(op->ptr, "x");
590         float y = RNA_int_get(op->ptr, "y");
591         float radius = RNA_int_get(op->ptr, "radius");
592
593         /* get editor data */
594         if (ANIM_animdata_get_context(C, &ac) == 0)
595                 return OPERATOR_CANCELLED;
596         
597         data.mval[0] = x;
598         data.mval[1] = y;
599         data.radius_squared = radius * radius;
600         data.rectf_view = &rect_fl;
601         
602         rect_fl.xmin = x - radius;
603         rect_fl.xmax = x + radius;
604         rect_fl.ymin = y - radius;
605         rect_fl.ymax = y + radius;
606         
607         /* apply region select action */
608         region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_CIRCLE, selectmode, &data);
609         
610         /* send notifier that keyframe selection has changed */
611         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
612         
613         return OPERATOR_FINISHED;
614 }
615
616 void ACTION_OT_select_circle(wmOperatorType *ot)
617 {
618         ot->name = "Circle Select";
619         ot->description = "Select keyframe points using circle selection";
620         ot->idname = "ACTION_OT_select_circle";
621         
622         ot->invoke = WM_gesture_circle_invoke;
623         ot->modal = WM_gesture_circle_modal;
624         ot->exec = action_circle_select_exec;
625         ot->poll = ED_operator_action_active;
626         ot->cancel = WM_gesture_circle_cancel;
627         
628         /* flags */
629         ot->flag = OPTYPE_UNDO;
630         
631         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
632         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
633         RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX);
634         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
635 }
636
637 /* ******************** Column Select Operator **************************** */
638 /* This operator works in one of four ways:
639  *      - 1) select all keyframes in the same frame as a selected one  (KKEY)
640  *      - 2) select all keyframes in the same frame as the current frame marker (CTRL-KKEY)
641  *      - 3) select all keyframes in the same frame as a selected markers (SHIFT-KKEY)
642  *      - 4) select all keyframes that occur between selected markers (ALT-KKEY)
643  */
644
645 /* defines for column-select mode */
646 static EnumPropertyItem prop_column_select_types[] = {
647         {ACTKEYS_COLUMNSEL_KEYS, "KEYS", 0, "On Selected Keyframes", ""},
648         {ACTKEYS_COLUMNSEL_CFRA, "CFRA", 0, "On Current Frame", ""},
649         {ACTKEYS_COLUMNSEL_MARKERS_COLUMN, "MARKERS_COLUMN", 0, "On Selected Markers", ""},
650         {ACTKEYS_COLUMNSEL_MARKERS_BETWEEN, "MARKERS_BETWEEN", 0, "Between Min/Max Selected Markers", ""},
651         {0, NULL, 0, NULL, NULL}
652 };
653
654 /* ------------------- */ 
655
656 /* Selects all visible keyframes between the specified markers */
657 /* TODO, this is almost an _exact_ duplicate of a function of the same name in graph_select.c
658  * should de-duplicate - campbell */
659 static void markers_selectkeys_between(bAnimContext *ac)
660 {
661         ListBase anim_data = {NULL, NULL};
662         bAnimListElem *ale;
663         int filter;
664         
665         KeyframeEditFunc ok_cb, select_cb;
666         KeyframeEditData ked = {{NULL}};
667         float min, max;
668         
669         /* get extreme markers */
670         ED_markers_get_minmax(ac->markers, 1, &min, &max);
671         min -= 0.5f;
672         max += 0.5f;
673         
674         /* get editing funcs + data */
675         ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
676         select_cb = ANIM_editkeyframes_select(SELECT_ADD);
677
678         ked.f1 = min;
679         ked.f2 = max;
680         
681         /* filter data */
682         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ | ANIMFILTER_NODUPLIS);
683         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
684         
685         /* select keys in-between */
686         for (ale = anim_data.first; ale; ale = ale->next) {
687                 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
688                 
689                 if (adt) {
690                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
691                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
692                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
693                 }
694                 else if (ale->type == ANIMTYPE_GPLAYER) {
695                         ED_gplayer_frames_select_border(ale->data, min, max, SELECT_ADD);
696                 }
697                 else if (ale->type == ANIMTYPE_MASKLAYER) {
698                         ED_masklayer_frames_select_border(ale->data, min, max, SELECT_ADD);
699                 }
700                 else {
701                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
702                 }
703         }
704         
705         /* Cleanup */
706         ANIM_animdata_freelist(&anim_data);
707 }
708
709
710 /* Selects all visible keyframes in the same frames as the specified elements */
711 static void columnselect_action_keys(bAnimContext *ac, short mode)
712 {
713         ListBase anim_data = {NULL, NULL};
714         bAnimListElem *ale;
715         int filter;
716         
717         Scene *scene = ac->scene;
718         CfraElem *ce;
719         KeyframeEditFunc select_cb, ok_cb;
720         KeyframeEditData ked = {{NULL}};
721         
722         /* initialize keyframe editing data */
723         
724         /* build list of columns */
725         switch (mode) {
726                 case ACTKEYS_COLUMNSEL_KEYS: /* list of selected keys */
727                         if (ac->datatype == ANIMCONT_GPENCIL) {
728                                 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE);
729                                 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
730                                 
731                                 for (ale = anim_data.first; ale; ale = ale->next)
732                                         ED_gplayer_make_cfra_list(ale->data, &ked.list, 1);
733                         }
734                         else {
735                                 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/);
736                                 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
737                                 
738                                 for (ale = anim_data.first; ale; ale = ale->next)
739                                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_to_cfraelem, NULL);
740                         }
741                         ANIM_animdata_freelist(&anim_data);
742                         break;
743                         
744                 case ACTKEYS_COLUMNSEL_CFRA: /* current frame */
745                         /* make a single CfraElem for storing this */
746                         ce = MEM_callocN(sizeof(CfraElem), "cfraElem");
747                         BLI_addtail(&ked.list, ce);
748                         
749                         ce->cfra = (float)CFRA;
750                         break;
751                         
752                 case ACTKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */
753                         ED_markers_make_cfra_list(ac->markers, &ked.list, SELECT);
754                         break;
755                         
756                 default: /* invalid option */
757                         return;
758         }
759         
760         /* set up BezTriple edit callbacks */
761         select_cb = ANIM_editkeyframes_select(SELECT_ADD);
762         ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAME);
763         
764         /* loop through all of the keys and select additional keyframes
765          * based on the keys found to be selected above
766          */
767         if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
768                 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE);
769         else
770                 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/);
771         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
772         
773         for (ale = anim_data.first; ale; ale = ale->next) {
774                 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
775                 
776                 /* loop over cfraelems (stored in the KeyframeEditData->list)
777                  *      - we need to do this here, as we can apply fewer NLA-mapping conversions
778                  */
779                 for (ce = ked.list.first; ce; ce = ce->next) {
780                         /* set frame for validation callback to refer to */
781                         if (adt)
782                                 ked.f1 = BKE_nla_tweakedit_remap(adt, ce->cfra, NLATIME_CONVERT_UNMAP);
783                         else
784                                 ked.f1 = ce->cfra;
785                         
786                         /* select elements with frame number matching cfraelem */
787                         if (ale->type == ANIMTYPE_GPLAYER)
788                                 ED_gpencil_select_frame(ale->data, ce->cfra, SELECT_ADD);
789                         else if (ale->type == ANIMTYPE_MASKLAYER)
790                                 ED_mask_select_frame(ale->data, ce->cfra, SELECT_ADD);
791                         else
792                                 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
793                 }
794         }
795         
796         /* free elements */
797         BLI_freelistN(&ked.list);
798         ANIM_animdata_freelist(&anim_data);
799 }
800
801 /* ------------------- */
802
803 static int actkeys_columnselect_exec(bContext *C, wmOperator *op)
804 {
805         bAnimContext ac;
806         short mode;
807         
808         /* get editor data */
809         if (ANIM_animdata_get_context(C, &ac) == 0)
810                 return OPERATOR_CANCELLED;
811                 
812         /* action to take depends on the mode */
813         mode = RNA_enum_get(op->ptr, "mode");
814         
815         if (mode == ACTKEYS_COLUMNSEL_MARKERS_BETWEEN)
816                 markers_selectkeys_between(&ac);
817         else
818                 columnselect_action_keys(&ac, mode);
819         
820         /* set notifier that keyframe selection have changed */
821         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
822         
823         return OPERATOR_FINISHED;
824 }
825  
826 void ACTION_OT_select_column(wmOperatorType *ot)
827 {
828         /* identifiers */
829         ot->name = "Select All";
830         ot->idname = "ACTION_OT_select_column";
831         ot->description = "Select all keyframes on the specified frame(s)";
832         
833         /* api callbacks */
834         ot->exec = actkeys_columnselect_exec;
835         ot->poll = ED_operator_action_active;
836         
837         /* flags */
838         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
839         
840         /* props */
841         ot->prop = RNA_def_enum(ot->srna, "mode", prop_column_select_types, 0, "Mode", "");
842 }
843
844 /* ******************** Select Linked Operator *********************** */
845
846 static int actkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
847 {
848         bAnimContext ac;
849         
850         ListBase anim_data = {NULL, NULL};
851         bAnimListElem *ale;
852         int filter;
853         
854         KeyframeEditFunc ok_cb = ANIM_editkeyframes_ok(BEZT_OK_SELECTED);
855         KeyframeEditFunc sel_cb = ANIM_editkeyframes_select(SELECT_ADD);
856         
857         /* get editor data */
858         if (ANIM_animdata_get_context(C, &ac) == 0)
859                 return OPERATOR_CANCELLED;
860         
861         /* loop through all of the keys and select additional keyframes based on these */
862         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
863         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
864         
865         for (ale = anim_data.first; ale; ale = ale->next) {
866                 FCurve *fcu = (FCurve *)ale->key_data;
867                 
868                 /* check if anything selected? */
869                 if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, ok_cb, NULL)) {
870                         /* select every keyframe in this curve then */
871                         ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL);
872                 }
873         }
874         
875         /* Cleanup */
876         ANIM_animdata_freelist(&anim_data);
877         
878         /* set notifier that keyframe selection has changed */
879         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
880         
881         return OPERATOR_FINISHED;
882 }
883
884 void ACTION_OT_select_linked(wmOperatorType *ot)
885 {
886         /* identifiers */
887         ot->name = "Select Linked";
888         ot->idname = "ACTION_OT_select_linked";
889         ot->description = "Select keyframes occurring in the same F-Curves as selected ones";
890         
891         /* api callbacks */
892         ot->exec = actkeys_select_linked_exec;
893         ot->poll = ED_operator_action_active;
894         
895         /* flags */
896         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
897 }
898
899 /* ******************** Select More/Less Operators *********************** */
900
901 /* Common code to perform selection */
902 static void select_moreless_action_keys(bAnimContext *ac, short mode)
903 {
904         ListBase anim_data = {NULL, NULL};
905         bAnimListElem *ale;
906         int filter;
907         
908         KeyframeEditData ked = {{NULL}};
909         KeyframeEditFunc build_cb;
910         
911         
912         /* init selmap building data */
913         build_cb = ANIM_editkeyframes_buildselmap(mode);
914         
915         /* loop through all of the keys and select additional keyframes based on these */
916         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
917         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
918         
919         for (ale = anim_data.first; ale; ale = ale->next) {
920                 FCurve *fcu = (FCurve *)ale->key_data;
921                 
922                 /* only continue if F-Curve has keyframes */
923                 if (fcu->bezt == NULL)
924                         continue;
925                 
926                 /* build up map of whether F-Curve's keyframes should be selected or not */
927                 ked.data = MEM_callocN(fcu->totvert, "selmap actEdit more");
928                 ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, build_cb, NULL);
929                 
930                 /* based on this map, adjust the selection status of the keyframes */
931                 ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, bezt_selmap_flush, NULL);
932                 
933                 /* free the selmap used here */
934                 MEM_freeN(ked.data);
935                 ked.data = NULL;
936         }
937         
938         /* Cleanup */
939         ANIM_animdata_freelist(&anim_data);
940 }
941
942 /* ----------------- */
943
944 static int actkeys_select_more_exec(bContext *C, wmOperator *UNUSED(op))
945 {
946         bAnimContext ac;
947         
948         /* get editor data */
949         if (ANIM_animdata_get_context(C, &ac) == 0)
950                 return OPERATOR_CANCELLED;
951         
952         /* perform select changes */
953         select_moreless_action_keys(&ac, SELMAP_MORE);
954         
955         /* set notifier that keyframe selection has changed */
956         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
957         
958         return OPERATOR_FINISHED;
959 }
960
961 void ACTION_OT_select_more(wmOperatorType *ot)
962 {
963         /* identifiers */
964         ot->name = "Select More";
965         ot->idname = "ACTION_OT_select_more";
966         ot->description = "Select keyframes beside already selected ones";
967         
968         /* api callbacks */
969         ot->exec = actkeys_select_more_exec;
970         ot->poll = ED_operator_action_active;
971         
972         /* flags */
973         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
974 }
975
976 /* ----------------- */
977
978 static int actkeys_select_less_exec(bContext *C, wmOperator *UNUSED(op))
979 {
980         bAnimContext ac;
981         
982         /* get editor data */
983         if (ANIM_animdata_get_context(C, &ac) == 0)
984                 return OPERATOR_CANCELLED;
985         
986         /* perform select changes */
987         select_moreless_action_keys(&ac, SELMAP_LESS);
988         
989         /* set notifier that keyframe selection has changed */
990         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
991         
992         return OPERATOR_FINISHED;
993 }
994
995 void ACTION_OT_select_less(wmOperatorType *ot)
996 {
997         /* identifiers */
998         ot->name = "Select Less";
999         ot->idname = "ACTION_OT_select_less";
1000         ot->description = "Deselect keyframes on ends of selection islands";
1001         
1002         /* api callbacks */
1003         ot->exec = actkeys_select_less_exec;
1004         ot->poll = ED_operator_action_active;
1005         
1006         /* flags */
1007         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1008 }
1009
1010 /* ******************** Select Left/Right Operator ************************* */
1011 /* Select keyframes left/right of the current frame indicator */
1012
1013 /* defines for left-right select tool */
1014 static EnumPropertyItem prop_actkeys_leftright_select_types[] = {
1015         {ACTKEYS_LRSEL_TEST, "CHECK", 0, "Check if Select Left or Right", ""},
1016         {ACTKEYS_LRSEL_LEFT, "LEFT", 0, "Before current frame", ""},
1017         {ACTKEYS_LRSEL_RIGHT, "RIGHT", 0, "After current frame", ""},
1018         {0, NULL, 0, NULL, NULL}
1019 };
1020
1021 /* --------------------------------- */
1022
1023 static void actkeys_select_leftright(bAnimContext *ac, short leftright, short select_mode)
1024 {
1025         ListBase anim_data = {NULL, NULL};
1026         bAnimListElem *ale;
1027         int filter;
1028         
1029         KeyframeEditFunc ok_cb, select_cb;
1030         KeyframeEditData ked = {{NULL}};
1031         Scene *scene = ac->scene;
1032         
1033         /* if select mode is replace, deselect all keyframes (and channels) first */
1034         if (select_mode == SELECT_REPLACE) {
1035                 select_mode = SELECT_ADD;
1036                 
1037                 /* - deselect all other keyframes, so that just the newly selected remain
1038                  * - channels aren't deselected, since we don't re-select any as a consequence
1039                  */
1040                 deselect_action_keys(ac, 0, SELECT_SUBTRACT);
1041         }
1042         
1043         /* set callbacks and editing data */
1044         ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
1045         select_cb = ANIM_editkeyframes_select(select_mode);
1046         
1047         if (leftright == ACTKEYS_LRSEL_LEFT) {
1048                 ked.f1 = MINAFRAMEF;
1049                 ked.f2 = (float)(CFRA + 0.1f);
1050         }
1051         else {
1052                 ked.f1 = (float)(CFRA - 0.1f);
1053                 ked.f2 = MAXFRAMEF;
1054         }
1055         
1056         /* filter data */
1057         if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
1058                 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
1059         else
1060                 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
1061         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1062                 
1063         /* select keys */
1064         for (ale = anim_data.first; ale; ale = ale->next) {
1065                 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
1066                 
1067                 if (adt) {
1068                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
1069                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
1070                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
1071                 }
1072                 else if (ale->type == ANIMTYPE_GPLAYER)
1073                         ED_gplayer_frames_select_border(ale->data, ked.f1, ked.f2, select_mode);
1074                 else if (ale->type == ANIMTYPE_MASKLAYER)
1075                         ED_masklayer_frames_select_border(ale->data, ked.f1, ked.f2, select_mode);
1076                 else
1077                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
1078         }
1079         
1080         /* Sync marker support */
1081         if (select_mode == SELECT_ADD) {
1082                 SpaceAction *saction = (SpaceAction *)ac->sl;
1083                 
1084                 if ((saction) && (saction->flag & SACTION_MARKERS_MOVE)) {
1085                         ListBase *markers = ED_animcontext_get_markers(ac);
1086                         TimeMarker *marker;
1087                         
1088                         for (marker = markers->first; marker; marker = marker->next) {
1089                                 if (((leftright == ACTKEYS_LRSEL_LEFT)  && (marker->frame <  CFRA)) ||
1090                                     ((leftright == ACTKEYS_LRSEL_RIGHT) && (marker->frame >= CFRA)))
1091                                 {
1092                                         marker->flag |= SELECT;
1093                                 }
1094                                 else {
1095                                         marker->flag &= ~SELECT;
1096                                 }
1097                         }
1098                 }
1099         }
1100
1101         /* Cleanup */
1102         ANIM_animdata_freelist(&anim_data);
1103 }
1104
1105 /* ----------------- */
1106
1107 static int actkeys_select_leftright_exec(bContext *C, wmOperator *op)
1108 {
1109         bAnimContext ac;
1110         short leftright = RNA_enum_get(op->ptr, "mode");
1111         short selectmode;
1112         
1113         /* get editor data */
1114         if (ANIM_animdata_get_context(C, &ac) == 0)
1115                 return OPERATOR_CANCELLED;
1116         
1117         /* select mode is either replace (deselect all, then add) or add/extend */
1118         if (RNA_boolean_get(op->ptr, "extend"))
1119                 selectmode = SELECT_INVERT;
1120         else
1121                 selectmode = SELECT_REPLACE;
1122                 
1123         /* if "test" mode is set, we don't have any info to set this with */
1124         if (leftright == ACTKEYS_LRSEL_TEST)
1125                 return OPERATOR_CANCELLED;
1126         
1127         /* do the selecting now */
1128         actkeys_select_leftright(&ac, leftright, selectmode);
1129         
1130         /* set notifier that keyframe selection (and channels too) have changed */
1131         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL);
1132         
1133         return OPERATOR_FINISHED;
1134 }
1135
1136 static int actkeys_select_leftright_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1137 {
1138         bAnimContext ac;
1139         short leftright = RNA_enum_get(op->ptr, "mode");
1140         
1141         /* get editor data */
1142         if (ANIM_animdata_get_context(C, &ac) == 0)
1143                 return OPERATOR_CANCELLED;
1144                 
1145         /* handle mode-based testing */
1146         if (leftright == ACTKEYS_LRSEL_TEST) {
1147                 Scene *scene = ac.scene;
1148                 ARegion *ar = ac.ar;
1149                 View2D *v2d = &ar->v2d;
1150                 float x;
1151
1152                 /* determine which side of the current frame mouse is on */
1153                 x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
1154                 if (x < CFRA)
1155                         RNA_enum_set(op->ptr, "mode", ACTKEYS_LRSEL_LEFT);
1156                 else
1157                         RNA_enum_set(op->ptr, "mode", ACTKEYS_LRSEL_RIGHT);
1158         }
1159         
1160         /* perform selection */
1161         return actkeys_select_leftright_exec(C, op);
1162 }
1163
1164 void ACTION_OT_select_leftright(wmOperatorType *ot)
1165 {
1166         PropertyRNA *prop;
1167         
1168         /* identifiers */
1169         ot->name = "Select Left/Right";
1170         ot->idname = "ACTION_OT_select_leftright";
1171         ot->description = "Select keyframes to the left or the right of the current frame";
1172         
1173         /* api callbacks  */
1174         ot->invoke = actkeys_select_leftright_invoke;
1175         ot->exec = actkeys_select_leftright_exec;
1176         ot->poll = ED_operator_action_active;
1177         
1178         /* flags */
1179         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1180         
1181         /* properties */
1182         ot->prop = RNA_def_enum(ot->srna, "mode", prop_actkeys_leftright_select_types, ACTKEYS_LRSEL_TEST, "Mode", "");
1183         RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
1184         
1185         prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
1186         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1187 }
1188
1189 /* ******************** Mouse-Click Select Operator *********************** */
1190 /* This operator works in one of three ways:
1191  *      - 1) keyframe under mouse - no special modifiers
1192  *      - 2) all keyframes on the same side of current frame indicator as mouse - ALT modifier
1193  *      - 3) column select all keyframes in frame under mouse - CTRL modifier
1194  *  - 4) all keyframes in channel under mouse - CTRL+ALT modifiers
1195  *
1196  * In addition to these basic options, the SHIFT modifier can be used to toggle the 
1197  * selection mode between replacing the selection (without) and inverting the selection (with).
1198  */
1199
1200 /* ------------------- */
1201  
1202 /* option 1) select keyframe directly under mouse */
1203 static void actkeys_mselect_single(bAnimContext *ac, bAnimListElem *ale, short select_mode, float selx)
1204 {
1205         KeyframeEditData ked = {{NULL}};
1206         KeyframeEditFunc select_cb, ok_cb;
1207         
1208         /* get functions for selecting keyframes */
1209         select_cb = ANIM_editkeyframes_select(select_mode);
1210         ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAME);
1211         ked.f1 = selx;
1212         ked.iterflags |= KED_F1_NLA_UNMAP;
1213         
1214         /* select the nominated keyframe on the given frame */
1215         if (ale->type == ANIMTYPE_GPLAYER) {
1216                 ED_gpencil_select_frame(ale->data, selx, select_mode);
1217         }
1218         else if (ale->type == ANIMTYPE_MASKLAYER) {
1219                 ED_mask_select_frame(ale->data, selx, select_mode);
1220         }
1221         else {
1222                 if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK) &&
1223                     (ale->type == ANIMTYPE_SUMMARY) && (ale->datatype == ALE_ALL))
1224                 {
1225                         ListBase anim_data = {NULL, NULL};
1226                         int filter;
1227                         
1228                         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ | ANIMFILTER_NODUPLIS);
1229                         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1230                         
1231                         for (ale = anim_data.first; ale; ale = ale->next) {
1232                                 if (ale->type == ANIMTYPE_GPLAYER) {
1233                                         ED_gpencil_select_frame(ale->data, selx, select_mode);
1234                                 }
1235                                 else if (ale->type == ANIMTYPE_MASKLAYER) {
1236                                         ED_mask_select_frame(ale->data, selx, select_mode);
1237                                 }
1238                         }
1239                         
1240                         ANIM_animdata_freelist(&anim_data);
1241                 }
1242                 else {
1243                         ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL);
1244                 }
1245         }
1246 }
1247
1248 /* Option 2) Selects all the keyframes on either side of the current frame (depends on which side the mouse is on) */
1249 /* (see actkeys_select_leftright) */
1250
1251 /* Option 3) Selects all visible keyframes in the same frame as the mouse click */
1252 static void actkeys_mselect_column(bAnimContext *ac, short select_mode, float selx)
1253 {
1254         ListBase anim_data = {NULL, NULL};
1255         bAnimListElem *ale;
1256         int filter;
1257         
1258         KeyframeEditFunc select_cb, ok_cb;
1259         KeyframeEditData ked = {{NULL}};
1260         
1261         /* set up BezTriple edit callbacks */
1262         select_cb = ANIM_editkeyframes_select(select_mode);
1263         ok_cb = ANIM_editkeyframes_ok(BEZT_OK_FRAME);
1264         
1265         /* loop through all of the keys and select additional keyframes
1266          * based on the keys found to be selected above
1267          */
1268         if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
1269                 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ | ANIMFILTER_NODUPLIS);
1270         else
1271                 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_NODUPLIS);
1272         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1273         
1274         for (ale = anim_data.first; ale; ale = ale->next) {
1275                 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
1276                 
1277                 /* set frame for validation callback to refer to */
1278                 if (adt)
1279                         ked.f1 = BKE_nla_tweakedit_remap(adt, selx, NLATIME_CONVERT_UNMAP);
1280                 else
1281                         ked.f1 = selx;
1282                 
1283                 /* select elements with frame number matching cfra */
1284                 if (ale->type == ANIMTYPE_GPLAYER)
1285                         ED_gpencil_select_frame(ale->key_data, selx, select_mode);
1286                 else if (ale->type == ANIMTYPE_MASKLAYER)
1287                         ED_mask_select_frame(ale->key_data, selx, select_mode);
1288                 else
1289                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
1290         }
1291         
1292         /* free elements */
1293         BLI_freelistN(&ked.list);
1294         ANIM_animdata_freelist(&anim_data);
1295 }
1296
1297 /* option 4) select all keyframes in same channel */
1298 static void actkeys_mselect_channel_only(bAnimContext *ac, bAnimListElem *ale, short select_mode)
1299 {
1300         KeyframeEditFunc select_cb;
1301         
1302         /* get functions for selecting keyframes */
1303         select_cb = ANIM_editkeyframes_select(select_mode);
1304         
1305         /* select all keyframes in this channel */
1306         if (ale->type == ANIMTYPE_GPLAYER) {
1307                 ED_gpencil_select_frames(ale->data, select_mode);
1308         }
1309         else if (ale->type == ANIMTYPE_MASKLAYER) {
1310                 ED_mask_select_frames(ale->data, select_mode);
1311         }
1312         else {
1313                 if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK) &&
1314                     (ale->type == ANIMTYPE_SUMMARY) && (ale->datatype == ALE_ALL))
1315                 {
1316                         ListBase anim_data = {NULL, NULL};
1317                         int filter;
1318                         
1319                         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE /*| ANIMFILTER_CURVESONLY */ | ANIMFILTER_NODUPLIS);
1320                         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1321                         
1322                         for (ale = anim_data.first; ale; ale = ale->next) {
1323                                 if (ale->type == ANIMTYPE_GPLAYER) {
1324                                         ED_gpencil_select_frames(ale->data, select_mode);
1325                                 }
1326                                 else if (ale->type == ANIMTYPE_MASKLAYER) {
1327                                         ED_mask_select_frames(ale->data, select_mode);
1328                                 }
1329                         }
1330                         
1331                         ANIM_animdata_freelist(&anim_data);
1332                 }
1333                 else {
1334                         ANIM_animchannel_keyframes_loop(NULL, ac->ads, ale, NULL, select_cb, NULL);
1335                 }
1336         }
1337 }
1338  
1339 /* ------------------- */
1340
1341 static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_mode, bool column, bool same_channel)
1342 {
1343         ListBase anim_data = {NULL, NULL};
1344         DLRBT_Tree anim_keys;
1345         bAnimListElem *ale;
1346         int filter;
1347         
1348         View2D *v2d = &ac->ar->v2d;
1349         bDopeSheet *ads = NULL;
1350         int channel_index;
1351         bool found = false;
1352         float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */
1353         float selx = 0.0f;  /* frame of keyframe under mouse */
1354         float x, y;
1355         rctf rectf;
1356         
1357         /* get dopesheet info */
1358         if (ac->datatype == ANIMCONT_DOPESHEET)
1359                 ads = ac->data;
1360         
1361         /* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */
1362         UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
1363         UI_view2d_listview_view_to_cell(v2d, 0, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
1364         
1365         /* x-range to check is +/- 7 (in screen/region-space) on either side of mouse click (size of keyframe icon) */
1366         UI_view2d_region_to_view(v2d, mval[0] - 7, mval[1], &rectf.xmin, &rectf.ymin);
1367         UI_view2d_region_to_view(v2d, mval[0] + 7, mval[1], &rectf.xmax, &rectf.ymax);
1368         
1369         /* filter data */
1370         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
1371         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1372         
1373         /* try to get channel */
1374         ale = BLI_findlink(&anim_data, channel_index);
1375         if (ale == NULL) {
1376                 /* channel not found */
1377                 printf("Error: animation channel (index = %d) not found in mouse_action_keys()\n", channel_index);
1378                 ANIM_animdata_freelist(&anim_data);
1379                 return;
1380         }
1381         else {
1382                 /* found match - must return here... */
1383                 AnimData *adt = ANIM_nla_mapping_get(ac, ale);
1384                 ActKeyColumn *ak, *akn = NULL;
1385                 
1386                 /* make list of keyframes */
1387                 BLI_dlrbTree_init(&anim_keys);
1388                 
1389                 if (ale->key_data) {
1390                         switch (ale->datatype) {
1391                                 case ALE_SCE:
1392                                 {
1393                                         Scene *scene = (Scene *)ale->key_data;
1394                                         scene_to_keylist(ads, scene, &anim_keys, NULL);
1395                                         break;
1396                                 }
1397                                 case ALE_OB:
1398                                 {
1399                                         Object *ob = (Object *)ale->key_data;
1400                                         ob_to_keylist(ads, ob, &anim_keys, NULL);
1401                                         break;
1402                                 }
1403                                 case ALE_ACT:
1404                                 {
1405                                         bAction *act = (bAction *)ale->key_data;
1406                                         action_to_keylist(adt, act, &anim_keys, NULL);
1407                                         break;
1408                                 }
1409                                 case ALE_FCURVE:
1410                                 {
1411                                         FCurve *fcu = (FCurve *)ale->key_data;
1412                                         fcurve_to_keylist(adt, fcu, &anim_keys, NULL);
1413                                         break;
1414                                 }
1415                         }
1416                 }
1417                 else if (ale->type == ANIMTYPE_SUMMARY) {
1418                         /* dopesheet summary covers everything */
1419                         summary_to_keylist(ac, &anim_keys, NULL);
1420                 }
1421                 else if (ale->type == ANIMTYPE_GROUP) {
1422                         // TODO: why don't we just give groups key_data too?
1423                         bActionGroup *agrp = (bActionGroup *)ale->data;
1424                         agroup_to_keylist(adt, agrp, &anim_keys, NULL);
1425                 }
1426                 else if (ale->type == ANIMTYPE_GPLAYER) {
1427                         // TODO: why don't we just give gplayers key_data too?
1428                         bGPDlayer *gpl = (bGPDlayer *)ale->data;
1429                         gpl_to_keylist(ads, gpl, &anim_keys);
1430                 }
1431                 else if (ale->type == ANIMTYPE_MASKLAYER) {
1432                         // TODO: why don't we just give masklayers key_data too?
1433                         MaskLayer *masklay = (MaskLayer *)ale->data;
1434                         mask_to_keylist(ads, masklay, &anim_keys);
1435                 }
1436
1437                 /* start from keyframe at root of BST, traversing until we find one within the range that was clicked on */
1438                 for (ak = anim_keys.root; ak; ak = akn) {
1439                         if (IN_RANGE(ak->cfra, rectf.xmin, rectf.xmax)) {
1440                                 /* set the frame to use, and apply inverse-correction for NLA-mapping 
1441                                  * so that the frame will get selected by the selection functions without
1442                                  * requiring to map each frame once again...
1443                                  */
1444                                 selx = BKE_nla_tweakedit_remap(adt, ak->cfra, NLATIME_CONVERT_UNMAP);
1445                                 frame = ak->cfra;
1446                                 found = true;
1447                                 break;
1448                         }
1449                         else if (ak->cfra < rectf.xmin)
1450                                 akn = ak->right;
1451                         else
1452                                 akn = ak->left;
1453                 }
1454                 
1455                 /* remove active channel from list of channels for separate treatment (since it's needed later on) */
1456                 BLI_remlink(&anim_data, ale);
1457                 
1458                 /* cleanup temporary lists */
1459                 BLI_dlrbTree_free(&anim_keys);
1460                 
1461                 /* free list of channels, since it's not used anymore */
1462                 ANIM_animdata_freelist(&anim_data);
1463         }
1464         
1465         /* for replacing selection, firstly need to clear existing selection */
1466         if (select_mode == SELECT_REPLACE) {
1467                 /* reset selection mode for next steps */
1468                 select_mode = SELECT_ADD;
1469                 
1470                 /* deselect all keyframes */
1471                 deselect_action_keys(ac, 0, SELECT_SUBTRACT);
1472                 
1473                 /* highlight channel clicked on */
1474                 if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET)) {
1475                         /* deselect all other channels first */
1476                         ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1477                         
1478                         /* Highlight Action-Group or F-Curve? */
1479                         if (ale && ale->data) {
1480                                 if (ale->type == ANIMTYPE_GROUP) {
1481                                         bActionGroup *agrp = ale->data;
1482                                         
1483                                         agrp->flag |= AGRP_SELECTED;
1484                                         ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
1485                                 }
1486                                 else if (ELEM(ale->type, ANIMTYPE_FCURVE, ANIMTYPE_NLACURVE)) {
1487                                         FCurve *fcu = ale->data;
1488                                         
1489                                         fcu->flag |= FCURVE_SELECTED;
1490                                         ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
1491                                 }
1492                         }
1493                 }
1494                 else if (ac->datatype == ANIMCONT_GPENCIL) {
1495                         /* deselect all other channels first */
1496                         ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1497                         
1498                         /* Highlight GPencil Layer */
1499                         if ((ale && ale->data) && (ale->type == ANIMTYPE_GPLAYER)) {
1500                                 bGPDlayer *gpl = ale->data;
1501                                 
1502                                 gpl->flag |= GP_LAYER_SELECT;
1503                                 //gpencil_layer_setactive(gpd, gpl);
1504                         }
1505                 }
1506                 else if (ac->datatype == ANIMCONT_MASK) {
1507                         /* deselect all other channels first */
1508                         ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1509
1510                         /* Highlight GPencil Layer */
1511                         if ((ale && ale->data) && (ale->type == ANIMTYPE_MASKLAYER)) {
1512                                 MaskLayer *masklay = ale->data;
1513
1514                                 masklay->flag |= MASK_LAYERFLAG_SELECT;
1515                                 //gpencil_layer_setactive(gpd, gpl);
1516                         }
1517                 }
1518         }
1519         
1520         /* only select keyframes if we clicked on a valid channel and hit something */
1521         if (ale) {
1522                 if (found) {
1523                         /* apply selection to keyframes */
1524                         if (column) {
1525                                 /* select all keyframes in the same frame as the one we hit on the active channel 
1526                                  * [T41077]: "frame" not "selx" here (i.e. no NLA corrections yet) as the code here
1527                                  *            does that itself again as it needs to work on multiple datablocks 
1528                                  */
1529                                 actkeys_mselect_column(ac, select_mode, frame);
1530                         }
1531                         else if (same_channel) {
1532                                 /* select all keyframes in the active channel */
1533                                 actkeys_mselect_channel_only(ac, ale, select_mode);     
1534                         }
1535                         else {
1536                                 /* select the nominated keyframe on the given frame */
1537                                 actkeys_mselect_single(ac, ale, select_mode, selx);
1538                         }
1539                 }
1540                 
1541                 /* free this channel */
1542                 MEM_freeN(ale);
1543         }
1544 }
1545
1546 /* handle clicking */
1547 static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1548 {
1549         bAnimContext ac;
1550         /* ARegion *ar; */ /* UNUSED */
1551         short selectmode;
1552         bool column, channel;
1553         
1554         /* get editor data */
1555         if (ANIM_animdata_get_context(C, &ac) == 0)
1556                 return OPERATOR_CANCELLED;
1557                 
1558         /* get useful pointers from animation context data */
1559         /* ar = ac.ar; */ /* UNUSED */
1560
1561         /* select mode is either replace (deselect all, then add) or add/extend */
1562         if (RNA_boolean_get(op->ptr, "extend"))
1563                 selectmode = SELECT_INVERT;
1564         else
1565                 selectmode = SELECT_REPLACE;
1566                 
1567         /* column selection */
1568         column = RNA_boolean_get(op->ptr, "column");
1569         channel = RNA_boolean_get(op->ptr, "channel");
1570         
1571         /* select keyframe(s) based upon mouse position*/
1572         mouse_action_keys(&ac, event->mval, selectmode, column, channel);
1573         
1574         /* set notifier that keyframe selection (and channels too) have changed */
1575         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL);
1576         
1577         /* for tweak grab to work */
1578         return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
1579 }
1580  
1581 void ACTION_OT_clickselect(wmOperatorType *ot)
1582 {
1583         PropertyRNA *prop;
1584         
1585         /* identifiers */
1586         ot->name = "Mouse Select Keys";
1587         ot->idname = "ACTION_OT_clickselect";
1588         ot->description = "Select keyframes by clicking on them";
1589         
1590         /* callbacks */
1591         ot->invoke = actkeys_clickselect_invoke;
1592         ot->poll = ED_operator_action_active;
1593         
1594         /* flags */
1595         ot->flag = OPTYPE_UNDO;
1596         
1597         /* properties */
1598         prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", 
1599                                "Toggle keyframe selection instead of leaving newly selected keyframes only"); // SHIFTKEY
1600         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1601         
1602         prop = RNA_def_boolean(ot->srna, "column", 0, "Column Select", 
1603                                "Select all keyframes that occur on the same frame as the one under the mouse"); // ALTKEY
1604         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1605         
1606         prop = RNA_def_boolean(ot->srna, "channel", 0, "Only Channel", 
1607                                "Select all the keyframes in the channel under the mouse"); // CTRLKEY + ALTKEY
1608         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1609 }
1610
1611 /* ************************************************************************** */