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