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