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