Batch renaming some keyframe editing internals in preparation for more generic keyfra...
[blender.git] / source / blender / editors / space_action / action_select.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation
21  *
22  * Contributor(s): Joshua Leung
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 #include <math.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <float.h>
31
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35
36 #include "MEM_guardedalloc.h"
37
38 #include "BLI_blenlib.h"
39 #include "BLI_math.h"
40 #include "BLI_dlrbTree.h"
41
42 #include "DNA_anim_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_scene_types.h"
45
46 #include "RNA_access.h"
47 #include "RNA_define.h"
48
49 #include "BKE_action.h"
50 #include "BKE_depsgraph.h"
51 #include "BKE_fcurve.h"
52 #include "BKE_key.h"
53 #include "BKE_material.h"
54 #include "BKE_nla.h"
55 #include "BKE_object.h"
56 #include "BKE_context.h"
57 #include "BKE_utildefines.h"
58
59 #include "UI_view2d.h"
60
61 #include "ED_anim_api.h"
62 #include "ED_keyframes_draw.h"
63 #include "ED_keyframes_edit.h"
64 #include "ED_markers.h"
65 #include "ED_screen.h"
66
67 #include "WM_api.h"
68 #include "WM_types.h"
69
70 #include "action_intern.h"
71
72 /* ************************************************************************** */
73 /* KEYFRAMES STUFF */
74
75 /* ******************** Deselect All Operator ***************************** */
76 /* This operator works in one of three ways:
77  *      1) (de)select all (AKEY) - test if select all or deselect all
78  *      2) invert all (CTRL-IKEY) - invert selection of all keyframes
79  *      3) (de)select all - no testing is done; only for use internal tools as normal function...
80  */
81
82 /* Deselects keyframes in the action editor
83  *      - This is called by the deselect all operator, as well as other ones!
84  *
85  *      - test: check if select or deselect all
86  *      - sel: how to select keyframes 
87  *              0 = deselect
88  *              1 = select
89  *              2 = invert
90  */
91 static void deselect_action_keys (bAnimContext *ac, short test, short sel)
92 {
93         ListBase anim_data = {NULL, NULL};
94         bAnimListElem *ale;
95         int filter;
96         
97         KeyframeEditData ked;
98         KeyframeEditFunc test_cb, sel_cb;
99         
100         /* determine type-based settings */
101         if (ac->datatype == ANIMCONT_GPENCIL)
102                 filter= (ANIMFILTER_VISIBLE);
103         else
104                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
105         
106         /* filter data */
107         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
108         
109         /* init BezTriple looping data */
110         memset(&ked, 0, sizeof(KeyframeEditData));
111         test_cb= ANIM_editkeyframes_ok(BEZT_OK_SELECTED);
112         
113         /* See if we should be selecting or deselecting */
114         if (test) {
115                 for (ale= anim_data.first; ale; ale= ale->next) {
116                         if (ale->type == ANIMTYPE_GPLAYER) {
117                                 //if (is_gplayer_frame_selected(ale->data)) {
118                                 //      sel= 0;
119                                 //      break;
120                                 //}
121                         }
122                         else {
123                                 if (ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, test_cb, NULL)) {
124                                         sel= SELECT_SUBTRACT;
125                                         break;
126                                 }
127                         }
128                 }
129         }
130         
131         /* convert sel to selectmode, and use that to get editor */
132         sel_cb= ANIM_editkeyframes_select(sel);
133         
134         /* Now set the flags */
135         for (ale= anim_data.first; ale; ale= ale->next) {
136                 //if (ale->type == ACTTYPE_GPLAYER)
137                 //      set_gplayer_frame_selection(ale->data, sel);
138                 //else
139                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, sel_cb, NULL);
140         }
141         
142         /* Cleanup */
143         BLI_freelistN(&anim_data);
144 }
145
146 /* ------------------- */
147
148 static int actkeys_deselectall_exec(bContext *C, wmOperator *op)
149 {
150         bAnimContext ac;
151         
152         /* get editor data */
153         if (ANIM_animdata_get_context(C, &ac) == 0)
154                 return OPERATOR_CANCELLED;
155                 
156         /* 'standard' behaviour - check if selected, then apply relevant selection */
157         if (RNA_boolean_get(op->ptr, "invert"))
158                 deselect_action_keys(&ac, 0, SELECT_INVERT);
159         else
160                 deselect_action_keys(&ac, 1, SELECT_ADD);
161         
162         /* set notifier that keyframe selection have changed */
163         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_SELECT, NULL);
164         
165         return OPERATOR_FINISHED;
166 }
167  
168 void ACTION_OT_select_all_toggle (wmOperatorType *ot)
169 {
170         /* identifiers */
171         ot->name= "Select All";
172         ot->idname= "ACTION_OT_select_all_toggle";
173         ot->description= "Toggle selection of all keyframes";
174         
175         /* api callbacks */
176         ot->exec= actkeys_deselectall_exec;
177         ot->poll= ED_operator_action_active;
178         
179         /* flags */
180         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
181         
182         /* props */
183         ot->prop= RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
184 }
185
186 /* ******************** Border Select Operator **************************** */
187 /* This operator currently works in one of three ways:
188  *      -> BKEY         - 1) all keyframes within region are selected (ACTKEYS_BORDERSEL_ALLKEYS)
189  *      -> ALT-BKEY - depending on which axis of the region was larger...
190  *              -> 2) x-axis, so select all frames within frame range (ACTKEYS_BORDERSEL_FRAMERANGE)
191  *              -> 3) y-axis, so select all frames within channels that region included (ACTKEYS_BORDERSEL_CHANNELS)
192  */
193
194 /* defines for borderselect mode */
195 enum {
196         ACTKEYS_BORDERSEL_ALLKEYS       = 0,
197         ACTKEYS_BORDERSEL_FRAMERANGE,
198         ACTKEYS_BORDERSEL_CHANNELS,
199 } eActKeys_BorderSelect_Mode;
200
201
202 static void borderselect_action (bAnimContext *ac, rcti rect, short mode, short selectmode)
203 {
204         ListBase anim_data = {NULL, NULL};
205         bAnimListElem *ale;
206         int filter, filterflag;
207         
208         KeyframeEditData ked;
209         KeyframeEditFunc ok_cb, select_cb;
210         View2D *v2d= &ac->ar->v2d;
211         rctf rectf;
212         float ymin=0, ymax=(float)(-ACHANNEL_HEIGHT_HALF);
213         
214         /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */
215         UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin+2, &rectf.xmin, &rectf.ymin);
216         UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax-2, &rectf.xmax, &rectf.ymax);
217         
218         /* filter data */
219         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
220         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
221         
222         /* get filtering flag for dopesheet data (if applicable) */
223         if (ac->datatype == ANIMCONT_DOPESHEET) {
224                 bDopeSheet *ads= (bDopeSheet *)ac->data;
225                 filterflag= ads->filterflag;
226         }
227         else
228                 filterflag= 0;
229         
230         /* get beztriple editing/validation funcs  */
231         select_cb= ANIM_editkeyframes_select(selectmode);
232         
233         if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS))
234                 ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
235         else
236                 ok_cb= NULL;
237                 
238         /* init editing data */
239         memset(&ked, 0, sizeof(KeyframeEditData));
240         
241         /* loop over data, doing border select */
242         for (ale= anim_data.first; ale; ale= ale->next) {
243                 AnimData *adt= ANIM_nla_mapping_get(ac, ale);
244                 
245                 /* get new vertical minimum extent of channel */
246                 ymin= ymax - ACHANNEL_STEP;
247                 
248                 /* set horizontal range (if applicable) */
249                 if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) {
250                         /* if channel is mapped in NLA, apply correction */
251                         if (adt) {
252                                 ked.f1= BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP);
253                                 ked.f2= BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP);
254                         }
255                         else {
256                                 ked.f1= rectf.xmin;
257                                 ked.f2= rectf.xmax;
258                         }
259                 }
260                 
261                 /* perform vertical suitability check (if applicable) */
262                 if ( (mode == ACTKEYS_BORDERSEL_FRAMERANGE) || 
263                         !((ymax < rectf.ymin) || (ymin > rectf.ymax)) )
264                 {
265                         /* loop over data selecting */
266                         //if (ale->type == ANIMTYPE_GPLAYER)
267                         //      borderselect_gplayer_frames(ale->data, rectf.xmin, rectf.xmax, selectmode);
268                         //else
269                                 ANIM_animchannel_keyframes_loop(&ked, ale, ok_cb, select_cb, NULL, filterflag);
270                 }
271                 
272                 /* set minimum extent to be the maximum of the next channel */
273                 ymax=ymin;
274         }
275         
276         /* cleanup */
277         BLI_freelistN(&anim_data);
278 }
279
280 /* ------------------- */
281
282 static int actkeys_borderselect_exec(bContext *C, wmOperator *op)
283 {
284         bAnimContext ac;
285         rcti rect;
286         short mode=0, selectmode=0;
287         int gesture_mode;
288         
289         /* get editor data */
290         if (ANIM_animdata_get_context(C, &ac) == 0)
291                 return OPERATOR_CANCELLED;
292         
293         /* get settings from operator */
294         rect.xmin= RNA_int_get(op->ptr, "xmin");
295         rect.ymin= RNA_int_get(op->ptr, "ymin");
296         rect.xmax= RNA_int_get(op->ptr, "xmax");
297         rect.ymax= RNA_int_get(op->ptr, "ymax");
298                 
299         gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
300         if (gesture_mode == GESTURE_MODAL_SELECT)
301                 selectmode = SELECT_ADD;
302         else
303                 selectmode = SELECT_SUBTRACT;
304         
305         /* selection 'mode' depends on whether borderselect region only matters on one axis */
306         if (RNA_boolean_get(op->ptr, "axis_range")) {
307                 /* mode depends on which axis of the range is larger to determine which axis to use 
308                  *      - checking this in region-space is fine, as it's fundamentally still going to be a different rect size
309                  *      - the frame-range select option is favoured over the channel one (x over y), as frame-range one is often
310                  *        used for tweaking timing when "blocking", while channels is not that useful...
311                  */
312                 if ((rect.xmax - rect.xmin) >= (rect.ymax - rect.ymin))
313                         mode= ACTKEYS_BORDERSEL_FRAMERANGE;
314                 else
315                         mode= ACTKEYS_BORDERSEL_CHANNELS;
316         }
317         else 
318                 mode= ACTKEYS_BORDERSEL_ALLKEYS;
319         
320         /* apply borderselect action */
321         borderselect_action(&ac, rect, mode, selectmode);
322         
323         /* set notifier that keyframe selection have changed */
324         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_SELECT, NULL);
325         
326         return OPERATOR_FINISHED;
327
328
329 void ACTION_OT_select_border(wmOperatorType *ot)
330 {
331         /* identifiers */
332         ot->name= "Border Select";
333         ot->idname= "ACTION_OT_select_border";
334         ot->description= "Select all keyframes within the specified region";
335         
336         /* api callbacks */
337         ot->invoke= WM_border_select_invoke;
338         ot->exec= actkeys_borderselect_exec;
339         ot->modal= WM_border_select_modal;
340         
341         ot->poll= ED_operator_action_active;
342         
343         /* flags */
344         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
345         
346         /* rna */
347         WM_operator_properties_gesture_border(ot, FALSE);
348         
349         ot->prop= RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", "");
350 }
351
352 /* ******************** Column Select Operator **************************** */
353 /* This operator works in one of four ways:
354  *      - 1) select all keyframes in the same frame as a selected one  (KKEY)
355  *      - 2) select all keyframes in the same frame as the current frame marker (CTRL-KKEY)
356  *      - 3) select all keyframes in the same frame as a selected markers (SHIFT-KKEY)
357  *      - 4) select all keyframes that occur between selected markers (ALT-KKEY)
358  */
359
360 /* defines for column-select mode */
361 static EnumPropertyItem prop_column_select_types[] = {
362         {ACTKEYS_COLUMNSEL_KEYS, "KEYS", 0, "On Selected Keyframes", ""},
363         {ACTKEYS_COLUMNSEL_CFRA, "CFRA", 0, "On Current Frame", ""},
364         {ACTKEYS_COLUMNSEL_MARKERS_COLUMN, "MARKERS_COLUMN", 0, "On Selected Markers", ""},
365         {ACTKEYS_COLUMNSEL_MARKERS_BETWEEN, "MARKERS_BETWEEN", 0, "Between Min/Max Selected Markers", ""},
366         {0, NULL, 0, NULL, NULL}
367 };
368
369 /* ------------------- */ 
370
371 /* Selects all visible keyframes between the specified markers */
372 static void markers_selectkeys_between (bAnimContext *ac)
373 {
374         ListBase anim_data = {NULL, NULL};
375         bAnimListElem *ale;
376         int filter;
377         
378         KeyframeEditFunc ok_cb, select_cb;
379         KeyframeEditData ked;
380         float min, max;
381         
382         /* get extreme markers */
383         ED_markers_get_minmax(ac->markers, 1, &min, &max);
384         min -= 0.5f;
385         max += 0.5f;
386         
387         /* get editing funcs + data */
388         ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
389         select_cb= ANIM_editkeyframes_select(SELECT_ADD);
390         
391         memset(&ked, 0, sizeof(KeyframeEditData));
392         ked.f1= min; 
393         ked.f2= max;
394         
395         /* filter data */
396         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
397         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
398         
399         /* select keys in-between */
400         for (ale= anim_data.first; ale; ale= ale->next) {
401                 AnimData *adt= ANIM_nla_mapping_get(ac, ale);
402                 
403                 if (adt) {
404                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
405                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
406                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
407                 }
408                 else {
409                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
410                 }
411         }
412         
413         /* Cleanup */
414         BLI_freelistN(&anim_data);
415 }
416
417
418 /* Selects all visible keyframes in the same frames as the specified elements */
419 static void columnselect_action_keys (bAnimContext *ac, short mode)
420 {
421         ListBase anim_data= {NULL, NULL};
422         bAnimListElem *ale;
423         int filter;
424         
425         Scene *scene= ac->scene;
426         CfraElem *ce;
427         KeyframeEditFunc select_cb, ok_cb;
428         KeyframeEditData ked;
429         
430         /* initialise keyframe editing data */
431         memset(&ked, 0, sizeof(KeyframeEditData));
432         
433         /* build list of columns */
434         switch (mode) {
435                 case ACTKEYS_COLUMNSEL_KEYS: /* list of selected keys */
436                         if (ac->datatype == ANIMCONT_GPENCIL) {
437                                 filter= (ANIMFILTER_VISIBLE);
438                                 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
439                                 
440                                 //for (ale= anim_data.first; ale; ale= ale->next)
441                                 //      gplayer_make_cfra_list(ale->data, &elems, 1);
442                         }
443                         else {
444                                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
445                                 ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
446                                 
447                                 for (ale= anim_data.first; ale; ale= ale->next)
448                                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_to_cfraelem, NULL);
449                         }
450                         BLI_freelistN(&anim_data);
451                         break;
452                         
453                 case ACTKEYS_COLUMNSEL_CFRA: /* current frame */
454                         /* make a single CfraElem for storing this */
455                         ce= MEM_callocN(sizeof(CfraElem), "cfraElem");
456                         BLI_addtail(&ked.list, ce);
457                         
458                         ce->cfra= (float)CFRA;
459                         break;
460                         
461                 case ACTKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */
462                         ED_markers_make_cfra_list(ac->markers, &ked.list, 1);
463                         break;
464                         
465                 default: /* invalid option */
466                         return;
467         }
468         
469         /* set up BezTriple edit callbacks */
470         select_cb= ANIM_editkeyframes_select(SELECT_ADD);
471         ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME);
472         
473         /* loop through all of the keys and select additional keyframes
474          * based on the keys found to be selected above
475          */
476         if (ac->datatype == ANIMCONT_GPENCIL)
477                 filter= (ANIMFILTER_VISIBLE);
478         else
479                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
480         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
481         
482         for (ale= anim_data.first; ale; ale= ale->next) {
483                 AnimData *adt= ANIM_nla_mapping_get(ac, ale);
484                 
485                 /* loop over cfraelems (stored in the KeyframeEditData->list)
486                  *      - we need to do this here, as we can apply fewer NLA-mapping conversions
487                  */
488                 for (ce= ked.list.first; ce; ce= ce->next) {
489                         /* set frame for validation callback to refer to */
490                         if (adt)
491                                 ked.f1= BKE_nla_tweakedit_remap(adt, ce->cfra, NLATIME_CONVERT_UNMAP);
492                         else
493                                 ked.f1= ce->cfra;
494                         
495                         /* select elements with frame number matching cfraelem */
496                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
497                         
498 #if 0 // XXX reenable when Grease Pencil stuff is back
499                         if (ale->type == ANIMTYPE_GPLAYER) {
500                                 bGPDlayer *gpl= (bGPDlayer *)ale->data;
501                                 bGPDframe *gpf;
502                                 
503                                 for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
504                                         if (ecfra == gpf->framenum) 
505                                                 gpf->flag |= GP_FRAME_SELECT;
506                                 }
507                         }
508                         //else... 
509 #endif // XXX reenable when Grease Pencil stuff is back
510                 }
511         }
512         
513         /* free elements */
514         BLI_freelistN(&ked.list);
515         BLI_freelistN(&anim_data);
516 }
517
518 /* ------------------- */
519
520 static int actkeys_columnselect_exec(bContext *C, wmOperator *op)
521 {
522         bAnimContext ac;
523         short mode;
524         
525         /* get editor data */
526         if (ANIM_animdata_get_context(C, &ac) == 0)
527                 return OPERATOR_CANCELLED;
528                 
529         /* action to take depends on the mode */
530         mode= RNA_enum_get(op->ptr, "mode");
531         
532         if (mode == ACTKEYS_COLUMNSEL_MARKERS_BETWEEN)
533                 markers_selectkeys_between(&ac);
534         else
535                 columnselect_action_keys(&ac, mode);
536         
537         /* set notifier that keyframe selection have changed */
538         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_SELECT, NULL);
539         
540         return OPERATOR_FINISHED;
541 }
542  
543 void ACTION_OT_select_column (wmOperatorType *ot)
544 {
545         /* identifiers */
546         ot->name= "Select All";
547         ot->idname= "ACTION_OT_select_column";
548         ot->description= "Select all keyframes on the specified frame(s)";
549         
550         /* api callbacks */
551         ot->exec= actkeys_columnselect_exec;
552         ot->poll= ED_operator_action_active;
553         
554         /* flags */
555         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
556         
557         /* props */
558         ot->prop= RNA_def_enum(ot->srna, "mode", prop_column_select_types, 0, "Mode", "");
559 }
560
561 /* ******************** Select More/Less Operators *********************** */
562
563 /* Common code to perform selection */
564 static void select_moreless_action_keys (bAnimContext *ac, short mode)
565 {
566         ListBase anim_data= {NULL, NULL};
567         bAnimListElem *ale;
568         int filter;
569         
570         KeyframeEditData ked;
571         KeyframeEditFunc build_cb;
572         
573         
574         /* init selmap building data */
575         build_cb= ANIM_editkeyframes_buildselmap(mode);
576         memset(&ked, 0, sizeof(KeyframeEditData)); 
577         
578         /* loop through all of the keys and select additional keyframes based on these */
579         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
580         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
581         
582         for (ale= anim_data.first; ale; ale= ale->next) {
583                 FCurve *fcu= (FCurve *)ale->key_data;
584                 
585                 /* only continue if F-Curve has keyframes */
586                 if (fcu->bezt == NULL)
587                         continue;
588                 
589                 /* build up map of whether F-Curve's keyframes should be selected or not */
590                 ked.data= MEM_callocN(fcu->totvert, "selmap actEdit more");
591                 ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, build_cb, NULL);
592                 
593                 /* based on this map, adjust the selection status of the keyframes */
594                 ANIM_fcurve_keyframes_loop(&ked, fcu, NULL, bezt_selmap_flush, NULL);
595                 
596                 /* free the selmap used here */
597                 MEM_freeN(ked.data);
598                 ked.data= NULL;
599         }
600         
601         /* Cleanup */
602         BLI_freelistN(&anim_data);
603 }
604
605 /* ----------------- */
606
607 static int actkeys_select_more_exec (bContext *C, wmOperator *op)
608 {
609         bAnimContext ac;
610         
611         /* get editor data */
612         if (ANIM_animdata_get_context(C, &ac) == 0)
613                 return OPERATOR_CANCELLED;
614         
615         /* perform select changes */
616         select_moreless_action_keys(&ac, SELMAP_MORE);
617         
618         /* set notifier that keyframe selection has changed */
619         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_SELECT, NULL);
620         
621         return OPERATOR_FINISHED;
622 }
623
624 void ACTION_OT_select_more (wmOperatorType *ot)
625 {
626         /* identifiers */
627         ot->name = "Select More";
628         ot->idname= "ACTION_OT_select_more";
629         ot->description = "Select keyframes beside already selected ones";
630         
631         /* api callbacks */
632         ot->exec= actkeys_select_more_exec;
633         ot->poll= ED_operator_action_active;
634         
635         /* flags */
636         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
637 }
638
639 /* ----------------- */
640
641 static int actkeys_select_less_exec (bContext *C, wmOperator *op)
642 {
643         bAnimContext ac;
644         
645         /* get editor data */
646         if (ANIM_animdata_get_context(C, &ac) == 0)
647                 return OPERATOR_CANCELLED;
648         
649         /* perform select changes */
650         select_moreless_action_keys(&ac, SELMAP_LESS);
651         
652         /* set notifier that keyframe selection has changed */
653         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_SELECT, NULL);
654         
655         return OPERATOR_FINISHED;
656 }
657
658 void ACTION_OT_select_less (wmOperatorType *ot)
659 {
660         /* identifiers */
661         ot->name = "Select Less";
662         ot->idname= "ACTION_OT_select_less";
663         ot->description = "Deselect keyframes on ends of selection islands";
664         
665         /* api callbacks */
666         ot->exec= actkeys_select_less_exec;
667         ot->poll= ED_operator_action_active;
668         
669         /* flags */
670         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
671 }
672
673 /* ******************** Mouse-Click Select Operator *********************** */
674 /* This operator works in one of three ways:
675  *      - 1) keyframe under mouse - no special modifiers
676  *      - 2) all keyframes on the same side of current frame indicator as mouse - ALT modifier
677  *      - 3) column select all keyframes in frame under mouse - CTRL modifier
678  *
679  * In addition to these basic options, the SHIFT modifier can be used to toggle the 
680  * selection mode between replacing the selection (without) and inverting the selection (with).
681  */
682
683 /* defines for left-right select tool */
684 static EnumPropertyItem prop_actkeys_leftright_select_types[] = {
685         {ACTKEYS_LRSEL_TEST, "CHECK", 0, "Check if Select Left or Right", ""},
686         {ACTKEYS_LRSEL_NONE, "OFF", 0, "Don't select", ""},
687         {ACTKEYS_LRSEL_LEFT, "LEFT", 0, "Before current frame", ""},
688         {ACTKEYS_LRSEL_RIGHT, "RIGHT", 0, "After current frame", ""},
689         {0, NULL, 0, NULL, NULL}
690 };
691
692 /* sensitivity factor for frame-selections */
693 #define FRAME_CLICK_THRESH              0.1f
694
695 /* ------------------- */
696  
697 /* option 1) select keyframe directly under mouse */
698 static void actkeys_mselect_single (bAnimContext *ac, bAnimListElem *ale, short select_mode, float selx)
699 {
700         bDopeSheet *ads= (ac->datatype == ANIMCONT_DOPESHEET) ? ac->data : NULL;
701         int ds_filter = ((ads) ? (ads->filterflag) : (0));
702         
703         KeyframeEditData ked;
704         KeyframeEditFunc select_cb, ok_cb;
705         
706         /* get functions for selecting keyframes */
707         select_cb= ANIM_editkeyframes_select(select_mode);
708         ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME);
709         memset(&ked, 0, sizeof(KeyframeEditData)); 
710         ked.f1= selx;
711         
712         /* select the nominated keyframe on the given frame */
713         ANIM_animchannel_keyframes_loop(&ked, ale, ok_cb, select_cb, NULL, ds_filter);
714 }
715
716 /* Option 2) Selects all the keyframes on either side of the current frame (depends on which side the mouse is on) */
717 static void actkeys_mselect_leftright (bAnimContext *ac, short leftright, short select_mode)
718 {
719         ListBase anim_data = {NULL, NULL};
720         bAnimListElem *ale;
721         int filter;
722         
723         KeyframeEditFunc ok_cb, select_cb;
724         KeyframeEditData ked;
725         Scene *scene= ac->scene;
726         
727         /* if select mode is replace, deselect all keyframes (and channels) first */
728         if (select_mode==SELECT_REPLACE) {
729                 select_mode= SELECT_ADD;
730                 
731                 /* deselect all other channels and keyframes */
732                 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
733                 deselect_action_keys(ac, 0, SELECT_SUBTRACT);
734         }
735         
736         /* set callbacks and editing data */
737         ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
738         select_cb= ANIM_editkeyframes_select(select_mode);
739         
740         memset(&ked, 0, sizeof(KeyframeEditFunc));
741         if (leftright == ACTKEYS_LRSEL_LEFT) {
742                 ked.f1 = MINAFRAMEF;
743                 ked.f2 = (float)(CFRA + FRAME_CLICK_THRESH);
744         } 
745         else {
746                 ked.f1 = (float)(CFRA - FRAME_CLICK_THRESH);
747                 ked.f2 = MAXFRAMEF;
748         }
749         
750         /* filter data */
751         if (ac->datatype == ANIMCONT_GPENCIL)
752                 filter= (ANIMFILTER_VISIBLE);
753         else
754                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
755         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
756                 
757         /* select keys on the side where most data occurs */
758         for (ale= anim_data.first; ale; ale= ale->next) {
759                 AnimData *adt= ANIM_nla_mapping_get(ac, ale);
760                 
761                 if (adt) {
762                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, 1);
763                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
764                         ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 1, 1);
765                 }
766                 //else if (ale->type == ANIMTYPE_GPLAYER)
767                 //      borderselect_gplayer_frames(ale->data, min, max, SELECT_ADD);
768                 else
769                         ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
770         }
771         
772         /* Sync marker support */
773         if((select_mode==SELECT_ADD) && (ac->spacetype==SPACE_ACTION) && ELEM(leftright, ACTKEYS_LRSEL_LEFT, ACTKEYS_LRSEL_RIGHT)) {
774                 SpaceAction *saction= ac->sa->spacedata.first;
775                 if (saction && saction->flag & SACTION_MARKERS_MOVE) {
776                         TimeMarker *marker;
777
778                         for (marker= scene->markers.first; marker; marker= marker->next) {
779                                 if(     ((leftright == ACTKEYS_LRSEL_LEFT) && marker->frame < CFRA) ||
780                                         ((leftright == ACTKEYS_LRSEL_RIGHT) && marker->frame >= CFRA)
781                                 ) {
782                                         marker->flag |= SELECT;
783                                 }
784                                 else {
785                                         marker->flag &= ~SELECT;
786                                 }
787                         }
788                 }
789         }
790
791         /* Cleanup */
792         BLI_freelistN(&anim_data);
793 }
794
795 /* Option 3) Selects all visible keyframes in the same frame as the mouse click */
796 static void actkeys_mselect_column(bAnimContext *ac, short select_mode, float selx)
797 {
798         ListBase anim_data= {NULL, NULL};
799         bAnimListElem *ale;
800         int filter;
801         
802         KeyframeEditFunc select_cb, ok_cb;
803         KeyframeEditData ked;
804         
805         /* initialise keyframe editing data */
806         memset(&ked, 0, sizeof(KeyframeEditData));
807         
808         /* set up BezTriple edit callbacks */
809         select_cb= ANIM_editkeyframes_select(select_mode);
810         ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME);
811         
812         /* loop through all of the keys and select additional keyframes
813          * based on the keys found to be selected above
814          */
815         if (ac->datatype == ANIMCONT_GPENCIL)
816                 filter= (ANIMFILTER_VISIBLE);
817         else
818                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
819         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
820         
821         for (ale= anim_data.first; ale; ale= ale->next) {
822                 AnimData *adt= ANIM_nla_mapping_get(ac, ale);
823                 
824                 /* set frame for validation callback to refer to */
825                 if (adt)
826                         ked.f1= BKE_nla_tweakedit_remap(adt, selx, NLATIME_CONVERT_UNMAP);
827                 else
828                         ked.f1= selx;
829                 
830                 /* select elements with frame number matching cfra */
831                 ANIM_fcurve_keyframes_loop(&ked, ale->key_data, ok_cb, select_cb, NULL);
832                         
833 #if 0 // XXX reenable when Grease Pencil stuff is back
834                         if (ale->type == ANIMTYPE_GPLAYER) {
835                                 bGPDlayer *gpl= (bGPDlayer *)ale->data;
836                                 bGPDframe *gpf;
837                                 
838                                 for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
839                                         if (ecfra == gpf->framenum) 
840                                                 gpf->flag |= GP_FRAME_SELECT;
841                                 }
842                         }
843                         //else... 
844 #endif // XXX reenable when Grease Pencil stuff is back
845         }
846         
847         /* free elements */
848         BLI_freelistN(&ked.list);
849         BLI_freelistN(&anim_data);
850 }
851  
852 /* ------------------- */
853
854 static void mouse_action_keys (bAnimContext *ac, int mval[2], short select_mode, short column)
855 {
856         ListBase anim_data = {NULL, NULL};
857         DLRBT_Tree anim_keys;
858         bAnimListElem *ale;
859         int filter;
860         
861         View2D *v2d= &ac->ar->v2d;
862         bDopeSheet *ads = NULL;
863         int channel_index;
864         short found = 0;
865         float selx = 0.0f;
866         float x, y;
867         rctf rectf;
868         
869         /* get dopesheet info */
870         if (ac->datatype == ANIMCONT_DOPESHEET)
871                 ads= ac->data;
872         
873         /* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */
874         UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
875         UI_view2d_listview_view_to_cell(v2d, 0, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
876         
877         /* x-range to check is +/- 7 (in screen/region-space) on either side of mouse click (size of keyframe icon) */
878         UI_view2d_region_to_view(v2d, mval[0]-7, mval[1], &rectf.xmin, &rectf.ymin);
879         UI_view2d_region_to_view(v2d, mval[0]+7, mval[1], &rectf.xmax, &rectf.ymax);
880         
881         /* filter data */
882         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
883         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
884         
885         /* try to get channel */
886         ale= BLI_findlink(&anim_data, channel_index);
887         if (ale == NULL) {
888                 /* channel not found */
889                 printf("Error: animation channel (index = %d) not found in mouse_action_keys() \n", channel_index);
890                 BLI_freelistN(&anim_data);
891                 return;
892         }
893         else {
894                 /* found match - must return here... */
895                 AnimData *adt= ANIM_nla_mapping_get(ac, ale);
896                 ActKeyColumn *ak, *akn=NULL;
897                 
898                 /* make list of keyframes */
899                 // TODO: it would be great if we didn't have to apply this to all the keyframes to do this...
900                 BLI_dlrbTree_init(&anim_keys);
901                 
902                 if (ale->key_data) {
903                         switch (ale->datatype) {
904                                 case ALE_SCE:
905                                 {
906                                         Scene *scene= (Scene *)ale->key_data;
907                                         scene_to_keylist(ads, scene, &anim_keys, NULL);
908                                 }
909                                         break;
910                                 case ALE_OB:
911                                 {
912                                         Object *ob= (Object *)ale->key_data;
913                                         ob_to_keylist(ads, ob, &anim_keys, NULL);
914                                 }
915                                         break;
916                                 case ALE_ACT:
917                                 {
918                                         bAction *act= (bAction *)ale->key_data;
919                                         action_to_keylist(adt, act, &anim_keys, NULL);
920                                 }
921                                         break;
922                                 case ALE_FCURVE:
923                                 {
924                                         FCurve *fcu= (FCurve *)ale->key_data;
925                                         fcurve_to_keylist(adt, fcu, &anim_keys, NULL);
926                                 }
927                                         break;
928                         }
929                 }
930                 else if (ale->type == ANIMTYPE_SUMMARY) {
931                         /* dopesheet summary covers everything */
932                         summary_to_keylist(ac, &anim_keys, NULL);
933                 }
934                 else if (ale->type == ANIMTYPE_GROUP) {
935                         bActionGroup *agrp= (bActionGroup *)ale->data;
936                         agroup_to_keylist(adt, agrp, &anim_keys, NULL);
937                 }
938                 else if (ale->type == ANIMTYPE_GPDATABLOCK) {
939                         /* cleanup */
940                         // FIXME:...
941                         BLI_freelistN(&anim_data);
942                         return;
943                 }
944                 else if (ale->type == ANIMTYPE_GPLAYER) {
945                         bGPDlayer *gpl= (bGPDlayer *)ale->data;
946                         gpl_to_keylist(ads, gpl, &anim_keys, NULL);
947                 }
948                 
949                 // the call below is not strictly necessary, since we have adjacency info anyway
950                 //BLI_dlrbTree_linkedlist_sync(&anim_keys);
951                 
952                 /* loop through keyframes, finding one that was within the range clicked on */
953                 for (ak= anim_keys.root; ak; ak= akn) {
954                         if (IN_RANGE(ak->cfra, rectf.xmin, rectf.xmax)) {
955                                 /* set the frame to use, and apply inverse-correction for NLA-mapping 
956                                  * so that the frame will get selected by the selection functiosn without
957                                  * requiring to map each frame once again...
958                                  */
959                                 selx= BKE_nla_tweakedit_remap(adt, ak->cfra, NLATIME_CONVERT_UNMAP);
960                                 found= 1;
961                                 break;
962                         }
963                         else if (ak->cfra < rectf.xmin)
964                                 akn= ak->right;
965                         else
966                                 akn= ak->left;
967                 }
968                 
969                 /* remove active channel from list of channels for separate treatment (since it's needed later on) */
970                 BLI_remlink(&anim_data, ale);
971                 
972                 /* cleanup temporary lists */
973                 BLI_dlrbTree_free(&anim_keys);
974                 
975                 /* free list of channels, since it's not used anymore */
976                 BLI_freelistN(&anim_data);
977         }
978         
979         /* for replacing selection, firstly need to clear existing selection */
980         if (select_mode == SELECT_REPLACE) {
981                 /* reset selection mode for next steps */
982                 select_mode = SELECT_ADD;
983                 
984                 /* deselect all keyframes */
985                 deselect_action_keys(ac, 0, SELECT_SUBTRACT);
986                 
987                 /* highlight channel clicked on */
988                 if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET)) {
989                         /* deselect all other channels first */
990                         ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
991                         
992                         /* Highlight Action-Group or F-Curve? */
993                         if (ale && ale->data) {
994                                 if (ale->type == ANIMTYPE_GROUP) {
995                                         bActionGroup *agrp= ale->data;
996                                         
997                                         agrp->flag |= AGRP_SELECTED;
998                                         ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
999                                 }       
1000                                 else if (ale->type == ANIMTYPE_FCURVE) {
1001                                         FCurve *fcu= ale->data;
1002                                         
1003                                         fcu->flag |= FCURVE_SELECTED;
1004                                         ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
1005                                 }
1006                         }
1007                 }
1008                 else if (ac->datatype == ANIMCONT_GPENCIL) {
1009                         ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1010                         
1011                         /* Highlight gpencil layer */
1012                         //gpl->flag |= GP_LAYER_SELECT;
1013                         //gpencil_layer_setactive(gpd, gpl);
1014                 }
1015         }
1016         
1017         /* only select keyframes if we clicked on a valid channel and hit something */
1018         if (ale) {
1019                 if (found) {
1020                         /* apply selection to keyframes */
1021                         if (/*gpl*/0) {
1022                                 /* grease pencil */
1023                                 //select_gpencil_frame(gpl, (int)selx, selectmode);
1024                         }
1025                         else if (column) {
1026                                 /* select all keyframes in the same frame as the one we hit on the active channel */
1027                                 actkeys_mselect_column(ac, select_mode, selx);
1028                         }
1029                         else {
1030                                 /* select the nominated keyframe on the given frame */
1031                                 actkeys_mselect_single(ac, ale, select_mode, selx);
1032                         }
1033                 }
1034                 
1035                 /* free this channel */
1036                 MEM_freeN(ale);
1037         }
1038 }
1039
1040 /* handle clicking */
1041 static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *event)
1042 {
1043         bAnimContext ac;
1044         Scene *scene;
1045         ARegion *ar;
1046         View2D *v2d;
1047         short selectmode, column;
1048         int mval[2];
1049         
1050         /* get editor data */
1051         if (ANIM_animdata_get_context(C, &ac) == 0)
1052                 return OPERATOR_CANCELLED;
1053                 
1054         /* get useful pointers from animation context data */
1055         scene= ac.scene;
1056         ar= ac.ar;
1057         v2d= &ar->v2d;
1058         
1059         /* get mouse coordinates (in region coordinates) */
1060         mval[0]= (event->x - ar->winrct.xmin);
1061         mval[1]= (event->y - ar->winrct.ymin);
1062         
1063         /* select mode is either replace (deselect all, then add) or add/extend */
1064         if (RNA_boolean_get(op->ptr, "extend"))
1065                 selectmode= SELECT_INVERT;
1066         else
1067                 selectmode= SELECT_REPLACE;
1068                 
1069         /* column selection */
1070         column= RNA_boolean_get(op->ptr, "column");
1071         
1072         /* figure out action to take */
1073         if (RNA_enum_get(op->ptr, "left_right")) {
1074                 /* select all keys on same side of current frame as mouse */
1075                 float x;
1076                 
1077                 UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, NULL);
1078                 if (x < CFRA)
1079                         RNA_int_set(op->ptr, "left_right", ACTKEYS_LRSEL_LEFT);
1080                 else    
1081                         RNA_int_set(op->ptr, "left_right", ACTKEYS_LRSEL_RIGHT);
1082                 
1083                 actkeys_mselect_leftright(&ac, RNA_enum_get(op->ptr, "left_right"), selectmode);
1084         }
1085         else {
1086                 /* select keyframe(s) based upon mouse position*/
1087                 mouse_action_keys(&ac, mval, selectmode, column);
1088         }
1089         
1090         /* set notifier that keyframe selection (and channels too) have changed */
1091         WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME_SELECT|ND_ANIMCHAN_SELECT, NULL);
1092         
1093         /* for tweak grab to work */
1094         return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
1095 }
1096  
1097 void ACTION_OT_clickselect (wmOperatorType *ot)
1098 {
1099         /* identifiers */
1100         ot->name= "Mouse Select Keys";
1101         ot->idname= "ACTION_OT_clickselect";
1102         ot->description= "Select keyframes by clicking on them";
1103         
1104         /* api callbacks - absolutely no exec() this yet... */
1105         ot->invoke= actkeys_clickselect_invoke;
1106         ot->poll= ED_operator_action_active;
1107         
1108         /* flags */
1109         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1110         
1111         /* id-props */
1112         // XXX should we make this into separate operators?
1113         RNA_def_enum(ot->srna, "left_right", prop_actkeys_leftright_select_types, 0, "Left Right", ""); // CTRLKEY
1114         RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
1115         RNA_def_boolean(ot->srna, "column", 0, "Column Select", ""); // ALTKEY
1116 }
1117
1118 /* ************************************************************************** */