Animato - Restoring most of Action Editor
[blender-staging.git] / source / blender / editors / space_action / action_select.c
1 /**
2  * $Id: editaction.c 17746 2008-12-08 11:19:44Z aligorith $
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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_arithb.h"
40
41 #include "DNA_anim_types.h"
42 #include "DNA_action_types.h"
43 #include "DNA_armature_types.h"
44 #include "DNA_camera_types.h"
45 #include "DNA_curve_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_screen_types.h"
48 #include "DNA_scene_types.h"
49 #include "DNA_space_types.h"
50 #include "DNA_constraint_types.h"
51 #include "DNA_key_types.h"
52 #include "DNA_lamp_types.h"
53 #include "DNA_material_types.h"
54 #include "DNA_userdef_types.h"
55 #include "DNA_gpencil_types.h"
56 #include "DNA_windowmanager_types.h"
57
58 #include "RNA_access.h"
59 #include "RNA_define.h"
60
61 #include "BKE_action.h"
62 #include "BKE_depsgraph.h"
63 #include "BKE_fcurve.h"
64 #include "BKE_key.h"
65 #include "BKE_material.h"
66 #include "BKE_object.h"
67 #include "BKE_context.h"
68 #include "BKE_utildefines.h"
69
70 #include "UI_view2d.h"
71
72 #include "ED_anim_api.h"
73 #include "ED_keyframing.h"
74 #include "ED_keyframes_draw.h"
75 #include "ED_keyframes_edit.h"
76 #include "ED_screen.h"
77 #include "ED_space_api.h"
78
79 #include "WM_api.h"
80 #include "WM_types.h"
81
82 #include "action_intern.h"
83
84 /* ************************************************************************** */
85 /* GENERAL STUFF */
86
87 /* used only by mouse_action. It is used to find the location of the nearest 
88  * keyframe to where the mouse clicked, 
89  */
90 // XXX port this to new listview code...
91 // XXX just merge this into the existing code!
92 static void *get_nearest_action_key (bAnimContext *ac, int mval[2], float *selx, short *sel, short *ret_type, bActionGroup **par)
93 {
94         ListBase anim_data = {NULL, NULL};
95         ListBase anim_keys = {NULL, NULL};
96         bAnimListElem *ale;
97         ActKeyColumn *ak;
98         View2D *v2d= &ac->ar->v2d;
99         int filter;
100         
101         rctf rectf;
102         void *data = NULL;
103         float xmin, xmax, x, y;
104         int channel_index;
105         short found = 0;
106         
107         /* action-group */
108         *par= NULL;
109         
110         
111         UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
112         UI_view2d_listview_view_to_cell(v2d, 0, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
113         
114         /* x-range to check is +/- 7 on either side of mouse click (size of keyframe icon) */
115         UI_view2d_region_to_view(v2d, mval[0]-7, mval[1], &rectf.xmin, &rectf.ymin);
116         UI_view2d_region_to_view(v2d, mval[0]+7, mval[1], &rectf.xmax, &rectf.ymax);
117         
118         /* filter data */
119         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
120         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
121         
122         /* get channel */
123         ale= BLI_findlink(&anim_data, channel_index);
124         if (ale == NULL) {
125                 /* channel not found */
126                 printf("Error: animation channel (index = %d) not found in mouse_action_keys() \n", channel_index);
127                 
128                 BLI_freelistN(&anim_data);
129                 return NULL;
130         }
131         
132         {
133                 /* found match - must return here... */
134                 Object *nob= ANIM_nla_mapping_get(ac, ale);
135                 ActKeysInc *aki= init_aki_data(ac, ale);
136                 
137                 /* apply NLA-scaling correction? */
138                 if (nob) {
139                         xmin= get_action_frame(nob, rectf.xmin);
140                         xmax= get_action_frame(nob, rectf.xmax);
141                 }
142                 else {
143                         xmin= rectf.xmin;
144                         xmax= rectf.xmax;
145                 }
146                 
147                 /* make list of keyframes */
148                 if (ale->key_data) {
149                         switch (ale->datatype) {
150                                 case ALE_OB:
151                                 {
152                                         Object *ob= (Object *)ale->key_data;
153                                         ob_to_keylist(ob, &anim_keys, NULL, aki);
154                                 }
155                                         break;
156                                 case ALE_ACT:
157                                 {
158                                         bAction *act= (bAction *)ale->key_data;
159                                         action_to_keylist(act, &anim_keys, NULL, aki);
160                                 }
161                                         break;
162                                 case ALE_FCURVE:
163                                 {
164                                         FCurve *fcu= (FCurve *)ale->key_data;
165                                         fcurve_to_keylist(fcu, &anim_keys, NULL, aki);
166                                 }
167                                         break;
168                         }
169                 }
170                 else if (ale->type == ANIMTYPE_GROUP) {
171                         bActionGroup *agrp= (bActionGroup *)ale->data;
172                         agroup_to_keylist(agrp, &anim_keys, NULL, aki);
173                 }
174                 else if (ale->type == ANIMTYPE_GPDATABLOCK) {
175                         /* cleanup */
176                         BLI_freelistN(&anim_data);
177                         
178                         /* this channel currently doens't have any keyframes... must ignore! */
179                         *ret_type= ANIMTYPE_NONE;
180                         return NULL;
181                 }
182                 else if (ale->type == ANIMTYPE_GPLAYER) {
183                         bGPDlayer *gpl= (bGPDlayer *)ale->data;
184                         gpl_to_keylist(gpl, &anim_keys, NULL, aki);
185                 }
186                 
187                 /* loop through keyframes, finding one that was clicked on */
188                 for (ak= anim_keys.first; ak; ak= ak->next) {
189                         if (IN_RANGE(ak->cfra, xmin, xmax)) {
190                                 *selx= ak->cfra;
191                                 found= 1;
192                                 break;
193                         }
194                 }
195                 /* no matching keyframe found - set to mean frame value so it doesn't actually select anything */
196                 if (found == 0)
197                         *selx= ((xmax+xmin) / 2);
198                 
199                 /* figure out what to return */
200                 if (ac->datatype == ANIMCONT_ACTION) {
201                         *par= ale->owner; /* assume that this is an action channel */
202                         *ret_type= ale->type;
203                         data = ale->data;
204                 }
205                 else if (ac->datatype == ANIMCONT_SHAPEKEY) {
206                         data = ale->key_data;
207                         *ret_type= ANIMTYPE_FCURVE;
208                 }
209                 else if (ac->datatype == ANIMCONT_DOPESHEET) {
210                         data = ale->data;
211                         *ret_type= ale->type;
212                 }
213                 else if (ac->datatype == ANIMCONT_GPENCIL) {
214                         data = ale->data;
215                         *ret_type= ANIMTYPE_GPLAYER;
216                 }
217                 
218                 /* cleanup tempolary lists */
219                 BLI_freelistN(&anim_keys);
220                 anim_keys.first = anim_keys.last = NULL;
221                 
222                 BLI_freelistN(&anim_data);
223                 
224                 return data;
225         }
226         
227         /* cleanup */
228         BLI_freelistN(&anim_data);
229         
230         *ret_type= ANIMTYPE_NONE;
231         return NULL;
232 }
233
234 /* ************************************************************************** */
235 /* KEYFRAMES STUFF */
236
237 /* ******************** Deselect All Operator ***************************** */
238 /* This operator works in one of three ways:
239  *      1) (de)select all (AKEY) - test if select all or deselect all
240  *      2) invert all (CTRL-IKEY) - invert selection of all keyframes
241  *      3) (de)select all - no testing is done; only for use internal tools as normal function...
242  */
243
244 /* Deselects keyframes in the action editor
245  *      - This is called by the deselect all operator, as well as other ones!
246  *
247  *      - test: check if select or deselect all
248  *      - sel: how to select keyframes 
249  *              0 = deselect
250  *              1 = select
251  *              2 = invert
252  */
253 static void deselect_action_keys (bAnimContext *ac, short test, short sel)
254 {
255         ListBase anim_data = {NULL, NULL};
256         bAnimListElem *ale;
257         int filter;
258         
259         BeztEditData bed;
260         BeztEditFunc test_cb, sel_cb;
261         
262         /* determine type-based settings */
263         if (ac->datatype == ANIMCONT_GPENCIL)
264                 filter= (ANIMFILTER_VISIBLE);
265         else
266                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
267         
268         /* filter data */
269         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
270         
271         /* init BezTriple looping data */
272         memset(&bed, 0, sizeof(BeztEditData));
273         test_cb= ANIM_editkeyframes_ok(BEZT_OK_SELECTED);
274         
275         /* See if we should be selecting or deselecting */
276         if (test) {
277                 for (ale= anim_data.first; ale; ale= ale->next) {
278                         if (ale->type == ANIMTYPE_GPLAYER) {
279                                 //if (is_gplayer_frame_selected(ale->data)) {
280                                 //      sel= 0;
281                                 //      break;
282                                 //}
283                         }
284                         else {
285                                 if (ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, test_cb, NULL)) {
286                                         sel= SELECT_SUBTRACT;
287                                         break;
288                                 }
289                         }
290                 }
291         }
292         
293         /* convert sel to selectmode, and use that to get editor */
294         sel_cb= ANIM_editkeyframes_select(sel);
295         
296         /* Now set the flags */
297         for (ale= anim_data.first; ale; ale= ale->next) {
298                 //if (ale->type == ACTTYPE_GPLAYER)
299                 //      set_gplayer_frame_selection(ale->data, sel);
300                 //else
301                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, sel_cb, NULL);
302         }
303         
304         /* Cleanup */
305         BLI_freelistN(&anim_data);
306 }
307
308 /* ------------------- */
309
310 static int actkeys_deselectall_exec(bContext *C, wmOperator *op)
311 {
312         bAnimContext ac;
313         
314         /* get editor data */
315         if (ANIM_animdata_get_context(C, &ac) == 0)
316                 return OPERATOR_CANCELLED;
317                 
318         /* 'standard' behaviour - check if selected, then apply relevant selection */
319         if (RNA_boolean_get(op->ptr, "invert"))
320                 deselect_action_keys(&ac, 0, SELECT_INVERT);
321         else
322                 deselect_action_keys(&ac, 1, SELECT_ADD);
323         
324         /* set notifier tha things have changed */
325         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
326         
327         return OPERATOR_FINISHED;
328 }
329  
330 void ACT_OT_keyframes_deselectall (wmOperatorType *ot)
331 {
332         /* identifiers */
333         ot->name= "Select All";
334         ot->idname= "ACT_OT_keyframes_deselectall";
335         
336         /* api callbacks */
337         ot->exec= actkeys_deselectall_exec;
338         ot->poll= ED_operator_areaactive;
339         
340         /* flags */
341         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
342         
343         /* props */
344         RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
345 }
346
347 /* ******************** Border Select Operator **************************** */
348 /* This operator currently works in one of three ways:
349  *      -> BKEY         - 1) all keyframes within region are selected (ACTKEYS_BORDERSEL_ALLKEYS)
350  *      -> ALT-BKEY - depending on which axis of the region was larger...
351  *              -> 2) x-axis, so select all frames within frame range (ACTKEYS_BORDERSEL_FRAMERANGE)
352  *              -> 3) y-axis, so select all frames within channels that region included (ACTKEYS_BORDERSEL_CHANNELS)
353  */
354
355 /* defines for borderselect mode */
356 enum {
357         ACTKEYS_BORDERSEL_ALLKEYS       = 0,
358         ACTKEYS_BORDERSEL_FRAMERANGE,
359         ACTKEYS_BORDERSEL_CHANNELS,
360 } eActKeys_BorderSelect_Mode;
361
362
363 static void borderselect_action (bAnimContext *ac, rcti rect, short mode, short selectmode)
364 {
365         ListBase anim_data = {NULL, NULL};
366         bAnimListElem *ale;
367         int filter;
368         
369         BeztEditData bed;
370         BeztEditFunc ok_cb, select_cb;
371         View2D *v2d= &ac->ar->v2d;
372         rctf rectf;
373         float ymin=0, ymax=(float)(-ACHANNEL_HEIGHT);
374         
375         /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */
376         UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin+2, &rectf.xmin, &rectf.ymin);
377         UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax-2, &rectf.xmax, &rectf.ymax);
378         
379         /* filter data */
380         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
381         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
382         
383         /* get beztriple editing/validation funcs  */
384         select_cb= ANIM_editkeyframes_select(selectmode);
385         
386         if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS))
387                 ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
388         else
389                 ok_cb= NULL;
390                 
391         /* init editing data */
392         memset(&bed, 0, sizeof(BeztEditData));
393         
394         /* loop over data, doing border select */
395         for (ale= anim_data.first; ale; ale= ale->next) {
396                 Object *nob= ANIM_nla_mapping_get(ac, ale);
397                 
398                 /* get new vertical minimum extent of channel */
399                 ymin= ymax - ACHANNEL_STEP;
400                 
401                 /* set horizontal range (if applicable) */
402                 if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) {
403                         /* if channel is mapped in NLA, apply correction */
404                         if (nob) {
405                                 bed.f1= get_action_frame(nob, rectf.xmin);
406                                 bed.f2= get_action_frame(nob, rectf.xmax);
407                         }
408                         else {
409                                 bed.f1= rectf.xmin;
410                                 bed.f2= rectf.xmax;
411                         }
412                 }
413                 
414                 /* perform vertical suitability check (if applicable) */
415                 if ( (mode == ACTKEYS_BORDERSEL_FRAMERANGE) || 
416                         !((ymax < rectf.ymin) || (ymin > rectf.ymax)) )
417                 {
418                         /* loop over data selecting */
419                         if (ale->key_data) {
420                                 if (ale->datatype == ALE_FCURVE)
421                                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
422                         }
423                         else if (ale->type == ANIMTYPE_GROUP) {
424                                 bActionGroup *agrp= ale->data;
425                                 FCurve *fcu;
426                                 
427                                 for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next) 
428                                         ANIM_fcurve_keys_bezier_loop(&bed, fcu, ok_cb, select_cb, NULL);
429                         }
430                         //else if (ale->type == ANIMTYPE_GPLAYER) {
431                         //      borderselect_gplayer_frames(ale->data, rectf.xmin, rectf.xmax, selectmode);
432                         //}
433                 }
434                 
435                 /* set minimum extent to be the maximum of the next channel */
436                 ymax=ymin;
437         }
438         
439         /* cleanup */
440         BLI_freelistN(&anim_data);
441 }
442
443 /* ------------------- */
444
445 static int actkeys_borderselect_exec(bContext *C, wmOperator *op)
446 {
447         bAnimContext ac;
448         rcti rect;
449         short mode=0, selectmode=0;
450         int event;
451         
452         /* get editor data */
453         if (ANIM_animdata_get_context(C, &ac) == 0)
454                 return OPERATOR_CANCELLED;
455         
456         /* get settings from operator */
457         rect.xmin= RNA_int_get(op->ptr, "xmin");
458         rect.ymin= RNA_int_get(op->ptr, "ymin");
459         rect.xmax= RNA_int_get(op->ptr, "xmax");
460         rect.ymax= RNA_int_get(op->ptr, "ymax");
461                 
462         event= RNA_int_get(op->ptr, "event_type");
463         if (event == LEFTMOUSE) // FIXME... hardcoded
464                 selectmode = SELECT_ADD;
465         else
466                 selectmode = SELECT_SUBTRACT;
467         
468         /* selection 'mode' depends on whether borderselect region only matters on one axis */
469         if (RNA_boolean_get(op->ptr, "axis_range")) {
470                 /* mode depends on which axis of the range is larger to determine which axis to use 
471                  *      - checking this in region-space is fine, as it's fundamentally still going to be a different rect size
472                  *      - the frame-range select option is favoured over the channel one (x over y), as frame-range one is often
473                  *        used for tweaking timing when "blocking", while channels is not that useful...
474                  */
475                 if ((rect.xmax - rect.xmin) >= (rect.ymax - rect.ymin))
476                         mode= ACTKEYS_BORDERSEL_FRAMERANGE;
477                 else
478                         mode= ACTKEYS_BORDERSEL_CHANNELS;
479         }
480         else 
481                 mode= ACTKEYS_BORDERSEL_ALLKEYS;
482         
483         /* apply borderselect action */
484         borderselect_action(&ac, rect, mode, selectmode);
485         
486         return OPERATOR_FINISHED;
487
488
489 void ACT_OT_keyframes_borderselect(wmOperatorType *ot)
490 {
491         /* identifiers */
492         ot->name= "Border Select";
493         ot->idname= "ACT_OT_keyframes_borderselect";
494         
495         /* api callbacks */
496         ot->invoke= WM_border_select_invoke;
497         ot->exec= actkeys_borderselect_exec;
498         ot->modal= WM_border_select_modal;
499         
500         ot->poll= ED_operator_areaactive;
501         
502         /* flags */
503         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
504         
505         /* rna */
506         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
507         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
508         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
509         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
510         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
511         
512         RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", "");
513 }
514
515 /* ******************** Column Select Operator **************************** */
516 /* This operator works in one of four ways:
517  *      - 1) select all keyframes in the same frame as a selected one  (KKEY)
518  *      - 2) select all keyframes in the same frame as the current frame marker (CTRL-KKEY)
519  *      - 3) select all keyframes in the same frame as a selected markers (SHIFT-KKEY)
520  *      - 4) select all keyframes that occur between selected markers (ALT-KKEY)
521  */
522
523 /* defines for column-select mode */
524 EnumPropertyItem prop_column_select_types[] = {
525         {ACTKEYS_COLUMNSEL_KEYS, "KEYS", "On Selected Keyframes", ""},
526         {ACTKEYS_COLUMNSEL_CFRA, "CFRA", "On Current Frame", ""},
527         {ACTKEYS_COLUMNSEL_MARKERS_COLUMN, "MARKERS_COLUMN", "On Selected Markers", ""},
528         {ACTKEYS_COLUMNSEL_MARKERS_BETWEEN, "MARKERS_BETWEEN", "Between Min/Max Selected Markers", ""},
529         {0, NULL, NULL, NULL}
530 };
531
532 /* ------------------- */ 
533
534 /* Selects all visible keyframes between the specified markers */
535 static void markers_selectkeys_between (bAnimContext *ac)
536 {
537         ListBase anim_data = {NULL, NULL};
538         bAnimListElem *ale;
539         int filter;
540         
541         BeztEditFunc select_cb;
542         BeztEditData bed;
543         float min, max;
544         
545         /* get extreme markers */
546         //get_minmax_markers(1, &min, &max); // FIXME... add back markers api!
547         min= (float)ac->scene->r.sfra; // xxx temp code
548         max= (float)ac->scene->r.efra; // xxx temp code
549         
550         if (min==max) return;
551         min -= 0.5f;
552         max += 0.5f;
553         
554         /* get editing funcs + data */
555         select_cb= ANIM_editkeyframes_select(SELECT_ADD);
556         memset(&bed, 0, sizeof(BeztEditData));
557         bed.f1= min; 
558         bed.f2= max;
559         
560         /* filter data */
561         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
562         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
563         
564         /* select keys in-between */
565         for (ale= anim_data.first; ale; ale= ale->next) {
566                 Object *nob= ANIM_nla_mapping_get(ac, ale);
567                 
568                 if (nob) {      
569                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1);
570                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, select_cb, NULL);
571                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
572                 }
573                 else {
574                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, select_cb, NULL);
575                 }
576         }
577         
578         /* Cleanup */
579         BLI_freelistN(&anim_data);
580 }
581
582
583 /* helper callback for columnselect_action_keys() -> populate list CfraElems with frame numbers from selected beztriples */
584 // TODO: if some other code somewhere needs this, it'll be time to port this over to keyframes_edit.c!!!
585 static short bezt_to_cfraelem(BeztEditData *bed, BezTriple *bezt)
586 {
587         /* only if selected */
588         if (bezt->f2 & SELECT) {
589                 CfraElem *ce= MEM_callocN(sizeof(CfraElem), "cfraElem");
590                 BLI_addtail(&bed->list, ce);
591                 
592                 ce->cfra= bezt->vec[1][0];
593         }
594         
595         return 0;
596 }
597
598 /* Selects all visible keyframes in the same frames as the specified elements */
599 static void columnselect_action_keys (bAnimContext *ac, short mode)
600 {
601         ListBase anim_data= {NULL, NULL};
602         bAnimListElem *ale;
603         int filter;
604         
605         Scene *scene= ac->scene;
606         CfraElem *ce;
607         BeztEditFunc select_cb, ok_cb;
608         BeztEditData bed;
609         
610         /* initialise keyframe editing data */
611         memset(&bed, 0, sizeof(BeztEditData));
612         
613         /* build list of columns */
614         switch (mode) {
615                 case ACTKEYS_COLUMNSEL_KEYS: /* list of selected keys */
616                         if (ac->datatype == ANIMCONT_GPENCIL) {
617                                 filter= (ANIMFILTER_VISIBLE);
618                                 ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
619                                 
620                                 //for (ale= anim_data.first; ale; ale= ale->next)
621                                 //      gplayer_make_cfra_list(ale->data, &elems, 1);
622                         }
623                         else {
624                                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
625                                 ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
626                                 
627                                 for (ale= anim_data.first; ale; ale= ale->next)
628                                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_to_cfraelem, NULL);
629                         }
630                         BLI_freelistN(&anim_data);
631                         break;
632                         
633                 case ACTKEYS_COLUMNSEL_CFRA: /* current frame */
634                         /* make a single CfraElem for storing this */
635                         ce= MEM_callocN(sizeof(CfraElem), "cfraElem");
636                         BLI_addtail(&bed.list, ce);
637                         
638                         ce->cfra= (float)CFRA;
639                         break;
640                         
641                 case ACTKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */
642                         // FIXME: markers api needs to be improved for this first!
643                         //make_marker_cfra_list(&elems, 1);
644                         return; // XXX currently, this does nothing!
645                         break;
646                         
647                 default: /* invalid option */
648                         return;
649         }
650         
651         /* set up BezTriple edit callbacks */
652         select_cb= ANIM_editkeyframes_select(SELECT_ADD);
653         ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME);
654         
655         /* loop through all of the keys and select additional keyframes
656          * based on the keys found to be selected above
657          */
658         if (ac->datatype == ANIMCONT_GPENCIL)
659                 filter= (ANIMFILTER_VISIBLE);
660         else
661                         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
662         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
663         
664         for (ale= anim_data.first; ale; ale= ale->next) {
665                 Object *nob= ANIM_nla_mapping_get(ac, ale);
666                 
667                 /* loop over cfraelems (stored in the BeztEditData->list)
668                  *      - we need to do this here, as we can apply fewer NLA-mapping conversions
669                  */
670                 for (ce= bed.list.first; ce; ce= ce->next) {
671                         /* set frame for validation callback to refer to */
672                         if (nob)
673                                 bed.f1= get_action_frame(nob, ce->cfra);
674                         else
675                                 bed.f1= ce->cfra;
676                         
677                         /* select elements with frame number matching cfraelem */
678                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
679                         
680 #if 0 // XXX reenable when Grease Pencil stuff is back
681                         if (ale->type == ANIMTYPE_GPLAYER) {
682                                 bGPDlayer *gpl= (bGPDlayer *)ale->data;
683                                 bGPDframe *gpf;
684                                 
685                                 for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
686                                         if (ecfra == gpf->framenum) 
687                                                 gpf->flag |= GP_FRAME_SELECT;
688                                 }
689                         }
690                         //else... 
691 #endif // XXX reenable when Grease Pencil stuff is back
692                 }
693         }
694         
695         /* free elements */
696         BLI_freelistN(&bed.list);
697         BLI_freelistN(&anim_data);
698 }
699
700 /* ------------------- */
701
702 static int actkeys_columnselect_exec(bContext *C, wmOperator *op)
703 {
704         bAnimContext ac;
705         short mode;
706         
707         /* get editor data */
708         if (ANIM_animdata_get_context(C, &ac) == 0)
709                 return OPERATOR_CANCELLED;
710                 
711         /* action to take depends on the mode */
712         mode= RNA_enum_get(op->ptr, "mode");
713         
714         if (mode == ACTKEYS_COLUMNSEL_MARKERS_BETWEEN)
715                 markers_selectkeys_between(&ac);
716         else
717                 columnselect_action_keys(&ac, mode);
718         
719         /* set notifier tha things have changed */
720         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_KEYFRAMES_SELECT);
721         
722         return OPERATOR_FINISHED;
723 }
724  
725 void ACT_OT_keyframes_columnselect (wmOperatorType *ot)
726 {
727         /* identifiers */
728         ot->name= "Select All";
729         ot->idname= "ACT_OT_keyframes_columnselect";
730         
731         /* api callbacks */
732         ot->exec= actkeys_columnselect_exec;
733         ot->poll= ED_operator_areaactive;
734         
735         /* flags */
736         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
737         
738         /* props */
739         RNA_def_enum(ot->srna, "mode", prop_column_select_types, 0, "Mode", "");
740 }
741
742 /* ******************** Mouse-Click Select Operator *********************** */
743 /* This operator works in one of three ways:
744  *      - 1) keyframe under mouse - no special modifiers
745  *      - 2) all keyframes on the same side of current frame indicator as mouse - ALT modifier
746  *      - 3) column select all keyframes in frame under mouse - CTRL modifier
747  *
748  * In addition to these basic options, the SHIFT modifier can be used to toggle the 
749  * selection mode between replacing the selection (without) and inverting the selection (with).
750  */
751
752 /* defines for left-right select tool */
753 EnumPropertyItem prop_leftright_select_types[] = {
754         {ACTKEYS_LRSEL_TEST, "CHECK", "Check if Select Left or Right", ""},
755         {ACTKEYS_LRSEL_NONE, "OFF", "Don't select", ""},
756         {ACTKEYS_LRSEL_LEFT, "LEFT", "Before current frame", ""},
757         {ACTKEYS_LRSEL_RIGHT, "RIGHT", "After current frame", ""},
758         {0, NULL, NULL, NULL}
759 };
760
761 /* ------------------- */
762  
763 /* option 1) select keyframe directly under mouse */
764 static void mouse_action_keys (bAnimContext *ac, int mval[2], short selectmode)
765 {
766         Object *ob= NULL;
767         bDopeSheet *ads= NULL;
768         bAction *act= NULL;
769         bActionGroup *agrp= NULL;
770         FCurve *fcu= NULL;
771         bGPdata *gpd = NULL;
772         bGPDlayer *gpl = NULL;
773         
774         BeztEditData bed;
775         BeztEditFunc select_cb, ok_cb;
776         void *anim_channel;
777         short sel, chan_type = 0;
778         float selx = 0.0f, selxa;
779         
780         /* determine what type of data we are operating on */
781         if (ac->datatype == ANIMCONT_ACTION) 
782                 act= (bAction *)ac->data;
783         else if (ac->datatype == ANIMCONT_DOPESHEET) 
784                 ads= (bDopeSheet *)ac->data;
785         else if (ac->datatype == ANIMCONT_GPENCIL) 
786                 gpd= (bGPdata *)ac->data;
787         
788         /* get channel and selection info */
789         anim_channel= get_nearest_action_key(ac, mval, &selx, &sel, &chan_type, &agrp); // xxx...
790         if (anim_channel == NULL) 
791                 return;
792         
793         switch (chan_type) {
794                 case ANIMTYPE_FCURVE:
795                         fcu= (FCurve *)anim_channel;
796                         break;
797                 case ANIMTYPE_GROUP:
798                         agrp= (bActionGroup *)anim_channel;
799                         break;
800 #if 0 // XXX fixme
801                 case ANIMTYPE_DSMAT:
802                         ipo= ((Material *)anim_channel)->ipo;
803                         break;
804                 case ANIMTYPE_DSLAM:
805                         ipo= ((Lamp *)anim_channel)->ipo;
806                         break;
807                 case ANIMTYPE_DSCAM:
808                         ipo= ((Camera *)anim_channel)->ipo;
809                         break;
810                 case ANIMTYPE_DSCUR:
811                         ipo= ((Curve *)anim_channel)->ipo;
812                         break;
813                 case ANIMTYPE_DSSKEY:
814                         ipo= ((Key *)anim_channel)->ipo;
815                         break;
816 #endif // XXX fixme
817                 case ANIMTYPE_FILLACTD:
818                         act= (bAction *)anim_channel;
819                         break;
820                 case ANIMTYPE_OBJECT:
821                         ob= ((Base *)anim_channel)->object;
822                         break;
823                 case ANIMTYPE_GPLAYER:
824                         gpl= (bGPDlayer *)anim_channel;
825                         break;
826                 default:
827                         return;
828         }
829         
830         /* for replacing selection, firstly need to clear existing selection */
831         if (selectmode == SELECT_REPLACE) {
832                 selectmode = SELECT_ADD;
833                 
834                 deselect_action_keys(ac, 0, SELECT_SUBTRACT);
835                 
836                 if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET)) {
837                         ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
838                         
839                         /* Highlight Action-Group? */
840                         if (agrp) {
841                                 agrp->flag |= AGRP_SELECTED;
842                                 ANIM_action_set_active_channel(ac->data, ac->datatype, agrp, ANIMTYPE_GROUP);
843                         }       
844                 }
845                 else if (ac->datatype == ANIMCONT_GPENCIL) {
846                         ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
847                         
848                         /* Highlight gpencil layer */
849                         gpl->flag |= GP_LAYER_SELECT;
850                         //gpencil_layer_setactive(gpd, gpl);
851                 }
852         }
853         
854         /* get functions for selecting keyframes */
855         select_cb= ANIM_editkeyframes_select(selectmode);
856         ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME);
857         memset(&bed, 0, sizeof(BeztEditData)); 
858         bed.f1= selx;
859         
860         /* apply selection to keyframes */
861         // XXX use more generic code looper for this stuff...
862         if (fcu)
863                 ANIM_fcurve_keys_bezier_loop(&bed, fcu, ok_cb, select_cb, NULL);
864         else if (agrp) {
865                 for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next)
866                         ANIM_fcurve_keys_bezier_loop(&bed, fcu, NULL, select_cb, NULL);
867         }
868         else if (act) {
869                 for (fcu= act->curves.first; fcu; fcu= fcu->next)
870                         ANIM_fcurve_keys_bezier_loop(&bed, fcu, NULL, select_cb, NULL);
871         }
872         else if (ob) {
873                 AnimData *adt;
874                 
875                 /* Object's own animation */
876                 if (ob->adt && ob->adt->action) {
877                         adt= ob->adt;
878                         
879                         selxa= get_action_frame(ob, selx); // xxx
880                         bed.f1= selxa;
881                         
882                         for (fcu= act->curves.first; fcu; fcu= fcu->next)
883                         ANIM_fcurve_keys_bezier_loop(&bed, fcu, NULL, select_cb, NULL);
884                 }
885                 
886                 /* 'Sub-Object' animation data */
887                 // TODO...
888         }
889         //else if (gpl)
890         //      select_gpencil_frame(gpl, (int)selx, selectmode);
891 }
892
893 /* Option 2) Selects all the keyframes on either side of the current frame (depends on which side the mouse is on) */
894 static void selectkeys_leftright (bAnimContext *ac, short leftright, short select_mode)
895 {
896         ListBase anim_data = {NULL, NULL};
897         bAnimListElem *ale;
898         int filter;
899         
900         BeztEditFunc ok_cb, select_cb;
901         BeztEditData bed;
902         Scene *scene= ac->scene;
903         
904         /* if select mode is replace, deselect all keyframes first */
905         if (select_mode==SELECT_REPLACE) {
906                 select_mode=SELECT_ADD;
907                 deselect_action_keys(ac, 0, SELECT_SUBTRACT);
908         }
909         
910         /* set callbacks and editing data */
911         ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
912         select_cb= ANIM_editkeyframes_select(select_mode);
913         
914         memset(&bed, 0, sizeof(BeztEditFunc));
915         if (leftright == ACTKEYS_LRSEL_LEFT) {
916                 bed.f1 = -MAXFRAMEF;
917                 bed.f2 = (float)(CFRA + 0.1f);
918         } 
919         else {
920                 bed.f1 = (float)(CFRA - 0.1f);
921                 bed.f2 = MAXFRAMEF;
922         }
923         
924         /* filter data */
925         if (ac->datatype == ANIMCONT_GPENCIL)
926                 filter= (ANIMFILTER_VISIBLE);
927         else
928                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
929         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
930                 
931         /* select keys on the side where most data occurs */
932         for (ale= anim_data.first; ale; ale= ale->next) {
933                 Object *nob= ANIM_nla_mapping_get(ac, ale);
934                 
935                 if (nob) {
936                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 0, 1);
937                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
938                         ANIM_nla_mapping_apply_fcurve(nob, ale->key_data, 1, 1);
939                 }
940                 //else if (ale->type == ANIMTYPE_GPLAYER)
941                 //      borderselect_gplayer_frames(ale->data, min, max, SELECT_ADD);
942                 else
943                         ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
944         }
945         
946         /* Cleanup */
947         BLI_freelistN(&anim_data);
948 }
949
950 /* Option 3) Selects all visible keyframes in the same frame as the mouse click */
951 static void mouse_columnselect_action_keys (bAnimContext *ac, float selx)
952 {
953         ListBase anim_data= {NULL, NULL};
954         bAnimListElem *ale;
955         int filter;
956         
957         BeztEditFunc select_cb, ok_cb;
958         BeztEditData bed;
959         
960         /* initialise keyframe editing data */
961         memset(&bed, 0, sizeof(BeztEditData));
962         
963         /* set up BezTriple edit callbacks */
964         select_cb= ANIM_editkeyframes_select(SELECT_ADD);
965         ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME);
966         
967         /* loop through all of the keys and select additional keyframes
968          * based on the keys found to be selected above
969          */
970         if (ac->datatype == ANIMCONT_GPENCIL)
971                 filter= (ANIMFILTER_VISIBLE);
972         else
973                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CURVESONLY);
974         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
975         
976         for (ale= anim_data.first; ale; ale= ale->next) {
977                 Object *nob= ANIM_nla_mapping_get(ac, ale);
978                 
979                 /* set frame for validation callback to refer to */
980                 if (nob)
981                         bed.f1= get_action_frame(nob, selx);
982                 else
983                         bed.f1= selx;
984                 
985                 /* select elements with frame number matching cfraelem */
986                 ANIM_fcurve_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
987                         
988 #if 0 // XXX reenable when Grease Pencil stuff is back
989                         if (ale->type == ANIMTYPE_GPLAYER) {
990                                 bGPDlayer *gpl= (bGPDlayer *)ale->data;
991                                 bGPDframe *gpf;
992                                 
993                                 for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
994                                         if (ecfra == gpf->framenum) 
995                                                 gpf->flag |= GP_FRAME_SELECT;
996                                 }
997                         }
998                         //else... 
999 #endif // XXX reenable when Grease Pencil stuff is back
1000         }
1001         
1002         /* free elements */
1003         BLI_freelistN(&bed.list);
1004         BLI_freelistN(&anim_data);
1005 }
1006  
1007 /* ------------------- */
1008
1009 /* handle clicking */
1010 static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *event)
1011 {
1012         bAnimContext ac;
1013         Scene *scene;
1014         ARegion *ar;
1015         View2D *v2d;
1016         short selectmode;
1017         int mval[2];
1018         
1019         /* get editor data */
1020         if (ANIM_animdata_get_context(C, &ac) == 0)
1021                 return OPERATOR_CANCELLED;
1022                 
1023         /* get useful pointers from animation context data */
1024         scene= ac.scene;
1025         ar= ac.ar;
1026         v2d= &ar->v2d;
1027         
1028         /* get mouse coordinates (in region coordinates) */
1029         mval[0]= (event->x - ar->winrct.xmin);
1030         mval[1]= (event->y - ar->winrct.ymin);
1031         
1032         /* select mode is either replace (deselect all, then add) or add/extend */
1033         // XXX this is currently only available for normal select only
1034         if (RNA_boolean_get(op->ptr, "extend_select"))
1035                 selectmode= SELECT_INVERT;
1036         else
1037                 selectmode= SELECT_REPLACE;
1038         
1039         /* figure out action to take */
1040         if (RNA_enum_get(op->ptr, "left_right")) {
1041                 /* select all keys on same side of current frame as mouse */
1042                 float x;
1043                 
1044                 UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, NULL);
1045                 if (x < CFRA)
1046                         RNA_int_set(op->ptr, "left_right", ACTKEYS_LRSEL_LEFT);
1047                 else    
1048                         RNA_int_set(op->ptr, "left_right", ACTKEYS_LRSEL_RIGHT);
1049                 
1050                 selectkeys_leftright(&ac, RNA_enum_get(op->ptr, "left_right"), selectmode);
1051         }
1052         else if (RNA_boolean_get(op->ptr, "column_select")) {
1053                 /* select all the keyframes that occur on the same frame as where the mouse clicked */
1054                 float x;
1055                 
1056                 /* figure out where (the frame) the mouse clicked, and set all keyframes in that frame */
1057                 UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, NULL);
1058                 mouse_columnselect_action_keys(&ac, x);
1059         }
1060         else {
1061                 /* select keyframe under mouse */
1062                 mouse_action_keys(&ac, mval, selectmode);
1063                 // XXX activate transform...
1064         }
1065         
1066         /* set notifier tha things have changed */
1067         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_BOTH);
1068         
1069         return OPERATOR_FINISHED;
1070 }
1071  
1072 void ACT_OT_keyframes_clickselect (wmOperatorType *ot)
1073 {
1074         /* identifiers */
1075         ot->name= "Mouse Select Keys";
1076         ot->idname= "ACT_OT_keyframes_clickselect";
1077         
1078         /* api callbacks */
1079         ot->invoke= actkeys_clickselect_invoke;
1080         ot->poll= ED_operator_areaactive;
1081         
1082         /* id-props */
1083         // XXX should we make this into separate operators?
1084         RNA_def_enum(ot->srna, "left_right", NULL /* XXX prop_actkeys_clickselect_items */, 0, "Left Right", ""); // ALTKEY
1085         RNA_def_boolean(ot->srna, "extend_select", 0, "Extend Select", ""); // SHIFTKEY
1086         RNA_def_boolean(ot->srna, "column_select", 0, "Column Select", ""); // CTRLKEY
1087 }
1088
1089 /* ************************************************************************** */