2.5 - Silencing more MSVC warnings
[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                                         ipo_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
419                                 else if (ale->datatype == ALE_ICU)
420                                         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                                         ipo_keys_bezier_loop(&bed, achan->ipo, ok_cb, select_cb, NULL);
429                                         
430                                         for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
431                                                 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         // XXX er...
508         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
509         
510         /* rna */
511         RNA_def_property(ot->srna, "event_type", PROP_INT, PROP_NONE);
512         RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
513         RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
514         RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
515         RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
516         
517         RNA_def_property(ot->srna, "axis_range", PROP_BOOLEAN, PROP_NONE);
518 }
519
520 /* ******************** Column Select Operator **************************** */
521 /* This operator works in one of four ways:
522  *      - 1) select all keyframes in the same frame as a selected one  (KKEY)
523  *      - 2) select all keyframes in the same frame as the current frame marker (CTRL-KKEY)
524  *      - 3) select all keyframes in the same frame as a selected markers (SHIFT-KKEY)
525  *      - 4) select all keyframes that occur between selected markers (ALT-KKEY)
526  */
527
528 /* defines for column-select mode */
529 EnumPropertyItem prop_column_select_types[] = {
530         {ACTKEYS_COLUMNSEL_KEYS, "KEYS", "On Selected Keyframes", ""},
531         {ACTKEYS_COLUMNSEL_CFRA, "CFRA", "On Current Frame", ""},
532         {ACTKEYS_COLUMNSEL_MARKERS_COLUMN, "MARKERS_COLUMN", "On Selected Markers", ""},
533         {ACTKEYS_COLUMNSEL_MARKERS_BETWEEN, "MARKERS_BETWEEN", "Between Min/Max Selected Markers", ""},
534         {0, NULL, NULL, NULL}
535 };
536
537 /* ------------------- */ 
538
539 /* Selects all visible keyframes between the specified markers */
540 static void markers_selectkeys_between (bAnimContext *ac)
541 {
542         ListBase anim_data = {NULL, NULL};
543         bAnimListElem *ale;
544         int filter;
545         
546         BeztEditFunc select_cb;
547         BeztEditData bed;
548         float min, max;
549         
550         /* get extreme markers */
551         //get_minmax_markers(1, &min, &max); // FIXME... add back markers api!
552         min= (float)ac->scene->r.sfra; // xxx temp code
553         max= (float)ac->scene->r.efra; // xxx temp code
554         
555         if (min==max) return;
556         min -= 0.5f;
557         max += 0.5f;
558         
559         /* get editing funcs + data */
560         select_cb= ANIM_editkeyframes_select(SELECT_ADD);
561         memset(&bed, 0, sizeof(BeztEditData));
562         bed.f1= min; 
563         bed.f2= max;
564         
565         /* filter data */
566         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_IPOKEYS);
567         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
568         
569         /* select keys in-between */
570         for (ale= anim_data.first; ale; ale= ale->next) {
571                 Object *nob= ANIM_nla_mapping_get(ac, ale);
572                 
573                 if (nob) {      
574                         ANIM_nla_mapping_apply(nob, ale->key_data, 0, 1);
575                         ipo_keys_bezier_loop(&bed, ale->key_data, NULL, select_cb, NULL);
576                         ANIM_nla_mapping_apply(nob, ale->key_data, 1, 1);
577                 }
578                 else {
579                         ipo_keys_bezier_loop(&bed, ale->key_data, NULL, select_cb, NULL);
580                 }
581         }
582         
583         /* Cleanup */
584         BLI_freelistN(&anim_data);
585 }
586
587
588 /* helper callback for columnselect_action_keys() -> populate list CfraElems with frame numbers from selected beztriples */
589 // TODO: if some other code somewhere needs this, it'll be time to port this over to keyframes_edit.c!!!
590 static short bezt_to_cfraelem(BeztEditData *bed, BezTriple *bezt)
591 {
592         /* only if selected */
593         if (bezt->f2 & SELECT) {
594                 CfraElem *ce= MEM_callocN(sizeof(CfraElem), "cfraElem");
595                 BLI_addtail(&bed->list, ce);
596                 
597                 ce->cfra= bezt->vec[1][0];
598         }
599         
600         return 0;
601 }
602
603 /* Selects all visible keyframes in the same frames as the specified elements */
604 static void columnselect_action_keys (bAnimContext *ac, short mode)
605 {
606         ListBase anim_data= {NULL, NULL};
607         bAnimListElem *ale;
608         int filter;
609         
610         Scene *scene= ac->scene;
611         CfraElem *ce;
612         BeztEditFunc select_cb, ok_cb;
613         BeztEditData bed;
614         
615         /* initialise keyframe editing data */
616         memset(&bed, 0, sizeof(BeztEditData));
617         
618         /* build list of columns */
619         switch (mode) {
620                 case ACTKEYS_COLUMNSEL_KEYS: /* list of selected keys */
621                         if (ac->datatype == ANIMCONT_GPENCIL) {
622                                 filter= (ANIMFILTER_VISIBLE);
623                                 ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
624                                 
625                                 //for (ale= anim_data.first; ale; ale= ale->next)
626                                 //      gplayer_make_cfra_list(ale->data, &elems, 1);
627                         }
628                         else {
629                                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_IPOKEYS);
630                                 ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
631                                 
632                                 for (ale= anim_data.first; ale; ale= ale->next)
633                                         ipo_keys_bezier_loop(&bed, ale->key_data, NULL, bezt_to_cfraelem, NULL);
634                         }
635                         BLI_freelistN(&anim_data);
636                         break;
637                         
638                 case ACTKEYS_COLUMNSEL_CFRA: /* current frame */
639                         /* make a single CfraElem for storing this */
640                         ce= MEM_callocN(sizeof(CfraElem), "cfraElem");
641                         BLI_addtail(&bed.list, ce);
642                         
643                         ce->cfra= (float)CFRA;
644                         break;
645                         
646                 case ACTKEYS_COLUMNSEL_MARKERS_COLUMN: /* list of selected markers */
647                         // FIXME: markers api needs to be improved for this first!
648                         //make_marker_cfra_list(&elems, 1);
649                         return; // XXX currently, this does nothing!
650                         break;
651                         
652                 default: /* invalid option */
653                         return;
654         }
655         
656         /* set up BezTriple edit callbacks */
657         select_cb= ANIM_editkeyframes_select(SELECT_ADD);
658         ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME);
659         
660         /* loop through all of the keys and select additional keyframes
661          * based on the keys found to be selected above
662          */
663         if (ac->datatype == ANIMCONT_GPENCIL)
664                 filter= (ANIMFILTER_VISIBLE);
665         else
666                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ONLYICU);
667         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
668         
669         for (ale= anim_data.first; ale; ale= ale->next) {
670                 Object *nob= ANIM_nla_mapping_get(ac, ale);
671                 
672                 /* loop over cfraelems (stored in the BeztEditData->list)
673                  *      - we need to do this here, as we can apply fewer NLA-mapping conversions
674                  */
675                 for (ce= bed.list.first; ce; ce= ce->next) {
676                         /* set frame for validation callback to refer to */
677                         if (nob)
678                                 bed.f1= get_action_frame(nob, ce->cfra);
679                         else
680                                 bed.f1= ce->cfra;
681                         
682                         /* select elements with frame number matching cfraelem */
683                         icu_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
684                         
685 #if 0 // XXX reenable when Grease Pencil stuff is back
686                         if (ale->type == ANIMTYPE_GPLAYER) {
687                                 bGPDlayer *gpl= (bGPDlayer *)ale->data;
688                                 bGPDframe *gpf;
689                                 
690                                 for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
691                                         if (ecfra == gpf->framenum) 
692                                                 gpf->flag |= GP_FRAME_SELECT;
693                                 }
694                         }
695                         //else... 
696 #endif // XXX reenable when Grease Pencil stuff is back
697                 }
698         }
699         
700         /* free elements */
701         BLI_freelistN(&bed.list);
702         BLI_freelistN(&anim_data);
703 }
704
705 /* ------------------- */
706
707 static int actkeys_columnselect_exec(bContext *C, wmOperator *op)
708 {
709         bAnimContext ac;
710         short mode;
711         
712         /* get editor data */
713         if (ANIM_animdata_get_context(C, &ac) == 0)
714                 return OPERATOR_CANCELLED;
715                 
716         /* action to take depends on the mode */
717         mode= RNA_enum_get(op->ptr, "mode");
718         
719         if (mode == ACTKEYS_COLUMNSEL_MARKERS_BETWEEN)
720                 markers_selectkeys_between(&ac);
721         else
722                 columnselect_action_keys(&ac, mode);
723         
724         /* set notifier tha things have changed */
725         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
726         
727         return OPERATOR_FINISHED;
728 }
729  
730 void ACT_OT_keyframes_columnselect (wmOperatorType *ot)
731 {
732         PropertyRNA *prop;
733         
734         /* identifiers */
735         ot->name= "Select All";
736         ot->idname= "ACT_OT_keyframes_columnselect";
737         
738         /* api callbacks */
739         ot->exec= actkeys_columnselect_exec;
740         ot->poll= ED_operator_areaactive;
741         
742         /* flags */
743         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
744         
745         /* props */
746         prop= RNA_def_property(ot->srna, "mode", PROP_ENUM, PROP_NONE);
747         RNA_def_property_enum_items(prop, prop_column_select_types);
748 }
749
750 /* ******************** Mouse-Click Select Operator *********************** */
751 /* This operator works in one of three ways:
752  *      - 1) keyframe under mouse - no special modifiers
753  *      - 2) all keyframes on the same side of current frame indicator as mouse - ALT modifier
754  *      - 3) column select all keyframes in frame under mouse - CTRL modifier
755  *
756  * In addition to these basic options, the SHIFT modifier can be used to toggle the 
757  * selection mode between replacing the selection (without) and inverting the selection (with).
758  */
759
760 /* defines for left-right select tool */
761 EnumPropertyItem prop_leftright_select_types[] = {
762         {ACTKEYS_LRSEL_TEST, "CHECK", "Check if Select Left or Right", ""},
763         {ACTKEYS_LRSEL_NONE, "OFF", "Don't select", ""},
764         {ACTKEYS_LRSEL_LEFT, "LEFT", "Before current frame", ""},
765         {ACTKEYS_LRSEL_RIGHT, "RIGHT", "After current frame", ""},
766         {0, NULL, NULL, NULL}
767 };
768
769 /* ------------------- */
770  
771 /* option 1) select keyframe directly under mouse */
772 static void mouse_action_keys (bAnimContext *ac, int mval[2], short selectmode)
773 {
774         Object *ob= NULL;
775         bDopeSheet *ads= NULL;
776         bAction *act= NULL;
777         bActionGroup *agrp= NULL;
778         bActionChannel *achan= NULL;
779         bConstraintChannel *conchan= NULL;
780         Ipo *ipo= NULL;
781         IpoCurve *icu= NULL;
782         bGPdata *gpd = NULL;
783         bGPDlayer *gpl = NULL;
784         
785         BeztEditData bed;
786         BeztEditFunc select_cb, ok_cb;
787         void *anim_channel;
788         short sel, chan_type = 0;
789         float selx = 0.0f, selxa;
790         
791         /* determine what type of data we are operating on */
792         if (ac->datatype == ANIMCONT_ACTION) 
793                 act= (bAction *)ac->data;
794         else if (ac->datatype == ANIMCONT_DOPESHEET) 
795                 ads= (bDopeSheet *)ac->data;
796         else if (ac->datatype == ANIMCONT_GPENCIL) 
797                 gpd= (bGPdata *)ac->data;
798         
799         /* get channel and selection info */
800         anim_channel= get_nearest_action_key(ac, mval, &selx, &sel, &chan_type, &achan);
801         if (anim_channel == NULL) 
802                 return;
803         
804         switch (chan_type) {
805                 case ANIMTYPE_ICU:
806                         icu= (IpoCurve *)anim_channel;
807                         break;
808                 case ANIMTYPE_CONCHAN:
809                         conchan= (bConstraintChannel *)anim_channel;
810                         break;
811                 case ANIMTYPE_ACHAN:
812                         achan= (bActionChannel *)anim_channel;
813                         break;
814                 case ANIMTYPE_GROUP:
815                         agrp= (bActionGroup *)anim_channel;
816                         break;
817                 case ANIMTYPE_DSMAT:
818                         ipo= ((Material *)anim_channel)->ipo;
819                         break;
820                 case ANIMTYPE_DSLAM:
821                         ipo= ((Lamp *)anim_channel)->ipo;
822                         break;
823                 case ANIMTYPE_DSCAM:
824                         ipo= ((Camera *)anim_channel)->ipo;
825                         break;
826                 case ANIMTYPE_DSCUR:
827                         ipo= ((Curve *)anim_channel)->ipo;
828                         break;
829                 case ANIMTYPE_DSSKEY:
830                         ipo= ((Key *)anim_channel)->ipo;
831                         break;
832                 case ANIMTYPE_FILLACTD:
833                         act= (bAction *)anim_channel;
834                         break;
835                 case ANIMTYPE_FILLIPOD:
836                         ipo= ((Object *)anim_channel)->ipo;
837                         break;
838                 case ANIMTYPE_OBJECT:
839                         ob= ((Base *)anim_channel)->object;
840                         break;
841                 case ANIMTYPE_GPLAYER:
842                         gpl= (bGPDlayer *)anim_channel;
843                         break;
844                 default:
845                         return;
846         }
847         
848         /* for replacing selection, firstly need to clear existing selection */
849         if (selectmode == SELECT_REPLACE) {
850                 selectmode = SELECT_ADD;
851                 
852                 deselect_action_keys(ac, 0, 0);
853                 
854                 if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET)) {
855                         ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
856                         
857                         /* Highlight either an Action-Channel or Action-Group */
858                         if (achan) {
859                                 achan->flag |= ACHAN_SELECTED;
860                                 //hilight_channel(act, achan, 1);
861                                 //select_poseelement_by_name(achan->name, 2);   /* 2 is activate */
862                         }
863                         else if (agrp) {
864                                 agrp->flag |= AGRP_SELECTED;
865                                 //set_active_actiongroup(act, agrp, 1);
866                         }
867                 }
868                 else if (ac->datatype == ANIMCONT_GPENCIL) {
869                         ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
870                         
871                         /* Highlight gpencil layer */
872                         gpl->flag |= GP_LAYER_SELECT;
873                         //gpencil_layer_setactive(gpd, gpl);
874                 }
875         }
876         
877         /* get functions for selecting keyframes */
878         select_cb= ANIM_editkeyframes_select(selectmode);
879         ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME);
880         memset(&bed, 0, sizeof(BeztEditData)); 
881         bed.f1= selx;
882         
883         /* apply selection to keyframes */
884         if (icu)
885                 icu_keys_bezier_loop(&bed, icu, ok_cb, select_cb, NULL);
886         else if (ipo)
887                 ipo_keys_bezier_loop(&bed, ipo, ok_cb, select_cb, NULL);
888         else if (conchan)
889                 ipo_keys_bezier_loop(&bed, conchan->ipo, ok_cb, select_cb, NULL);
890         else if (achan)
891                 ipo_keys_bezier_loop(&bed, achan->ipo, ok_cb, select_cb, NULL);
892         else if (agrp) {
893                 for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next) {
894                         ipo_keys_bezier_loop(&bed, achan->ipo, ok_cb, select_cb, NULL);
895                         
896                         for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
897                                 ipo_keys_bezier_loop(&bed, conchan->ipo, ok_cb, select_cb, NULL);
898                 }
899         }
900         else if (act) {
901                 for (achan= act->chanbase.first; achan; achan= achan->next) {
902                         ipo_keys_bezier_loop(&bed, achan->ipo, ok_cb, select_cb, NULL);
903                         
904                         for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
905                                 ipo_keys_bezier_loop(&bed, conchan->ipo, ok_cb, select_cb, NULL);
906                 }
907         }
908         else if (ob) {
909                 if (ob->ipo) {
910                         bed.f1= selx;
911                         ipo_keys_bezier_loop(&bed, ob->ipo, ok_cb, select_cb, NULL);
912                 }
913                 
914                 if (ob->action) {
915                         selxa= get_action_frame(ob, selx);
916                         bed.f1= selxa;
917                         
918                         for (achan= ob->action->chanbase.first; achan; achan= achan->next) {
919                                 ipo_keys_bezier_loop(&bed, achan->ipo, ok_cb, select_cb, NULL);
920                                 
921                                 for (conchan=achan->constraintChannels.first; conchan; conchan=conchan->next)
922                                         ipo_keys_bezier_loop(&bed, conchan->ipo, ok_cb, select_cb, NULL);
923                         }
924                 }
925                 
926                 if (ob->constraintChannels.first) {
927                         bed.f1= selx;
928                         
929                         for (conchan=ob->constraintChannels.first; conchan; conchan=conchan->next)
930                                 ipo_keys_bezier_loop(&bed, conchan->ipo, ok_cb, select_cb, NULL);
931                 }
932                 
933                 // FIXME: add data ipos too...
934         }
935         //else if (gpl)
936         //      select_gpencil_frame(gpl, (int)selx, selectmode);
937 }
938
939 /* Option 2) Selects all the keyframes on either side of the current frame (depends on which side the mouse is on) */
940 static void selectkeys_leftright (bAnimContext *ac, short leftright, short select_mode)
941 {
942         ListBase anim_data = {NULL, NULL};
943         bAnimListElem *ale;
944         int filter;
945         
946         BeztEditFunc ok_cb, select_cb;
947         BeztEditData bed;
948         Scene *scene= ac->scene;
949         
950         /* if select mode is replace, deselect all keyframes first */
951         if (select_mode==SELECT_REPLACE) {
952                 select_mode=SELECT_ADD;
953                 deselect_action_keys(ac, 0, 0);
954         }
955         
956         /* set callbacks and editing data */
957         ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAMERANGE);
958         select_cb= ANIM_editkeyframes_select(select_mode);
959         
960         memset(&bed, 0, sizeof(BeztEditFunc));
961         if (leftright == ACTKEYS_LRSEL_LEFT) {
962                 bed.f1 = -MAXFRAMEF;
963                 bed.f2 = (float)(CFRA + 0.1f);
964         } 
965         else {
966                 bed.f1 = (float)(CFRA - 0.1f);
967                 bed.f2 = MAXFRAMEF;
968         }
969         
970         /* filter data */
971         if (ac->datatype == ANIMCONT_GPENCIL)
972                 filter= (ANIMFILTER_VISIBLE);
973         else
974                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_IPOKEYS);
975         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
976                 
977         /* select keys on the side where most data occurs */
978         for (ale= anim_data.first; ale; ale= ale->next) {
979                 Object *nob= ANIM_nla_mapping_get(ac, ale);
980                 
981                 if (nob) {
982                         ANIM_nla_mapping_apply(nob, ale->key_data, 0, 1);
983                         ipo_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
984                         ANIM_nla_mapping_apply(nob, ale->key_data, 1, 1);
985                 }
986                 //else if (ale->type == ANIMTYPE_GPLAYER)
987                 //      borderselect_gplayer_frames(ale->data, min, max, SELECT_ADD);
988                 else
989                         ipo_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
990         }
991         
992         /* Cleanup */
993         BLI_freelistN(&anim_data);
994 }
995
996 /* Option 3) Selects all visible keyframes in the same frame as the mouse click */
997 static void mouse_columnselect_action_keys (bAnimContext *ac, float selx)
998 {
999         ListBase anim_data= {NULL, NULL};
1000         bAnimListElem *ale;
1001         int filter;
1002         
1003         BeztEditFunc select_cb, ok_cb;
1004         BeztEditData bed;
1005         
1006         /* initialise keyframe editing data */
1007         memset(&bed, 0, sizeof(BeztEditData));
1008         
1009         /* set up BezTriple edit callbacks */
1010         select_cb= ANIM_editkeyframes_select(SELECT_ADD);
1011         ok_cb= ANIM_editkeyframes_ok(BEZT_OK_FRAME);
1012         
1013         /* loop through all of the keys and select additional keyframes
1014          * based on the keys found to be selected above
1015          */
1016         if (ac->datatype == ANIMCONT_GPENCIL)
1017                 filter= (ANIMFILTER_VISIBLE);
1018         else
1019                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_ONLYICU);
1020         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
1021         
1022         for (ale= anim_data.first; ale; ale= ale->next) {
1023                 Object *nob= ANIM_nla_mapping_get(ac, ale);
1024                 
1025                 /* set frame for validation callback to refer to */
1026                 if (nob)
1027                         bed.f1= get_action_frame(nob, selx);
1028                 else
1029                         bed.f1= selx;
1030                 
1031                 /* select elements with frame number matching cfraelem */
1032                 icu_keys_bezier_loop(&bed, ale->key_data, ok_cb, select_cb, NULL);
1033                         
1034 #if 0 // XXX reenable when Grease Pencil stuff is back
1035                         if (ale->type == ANIMTYPE_GPLAYER) {
1036                                 bGPDlayer *gpl= (bGPDlayer *)ale->data;
1037                                 bGPDframe *gpf;
1038                                 
1039                                 for (gpf= gpl->frames.first; gpf; gpf= gpf->next) {
1040                                         if (ecfra == gpf->framenum) 
1041                                                 gpf->flag |= GP_FRAME_SELECT;
1042                                 }
1043                         }
1044                         //else... 
1045 #endif // XXX reenable when Grease Pencil stuff is back
1046         }
1047         
1048         /* free elements */
1049         BLI_freelistN(&bed.list);
1050         BLI_freelistN(&anim_data);
1051 }
1052  
1053 /* ------------------- */
1054
1055 /* handle clicking */
1056 static int actkeys_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *event)
1057 {
1058         bAnimContext ac;
1059         Scene *scene;
1060         ARegion *ar;
1061         View2D *v2d;
1062         short selectmode;
1063         int mval[2];
1064         
1065         /* get editor data */
1066         if (ANIM_animdata_get_context(C, &ac) == 0)
1067                 return OPERATOR_CANCELLED;
1068                 
1069         /* get useful pointers from animation context data */
1070         scene= ac.scene;
1071         ar= ac.ar;
1072         v2d= &ar->v2d;
1073         
1074         /* get mouse coordinates (in region coordinates) */
1075         mval[0]= (event->x - ar->winrct.xmin);
1076         mval[1]= (event->y - ar->winrct.ymin);
1077         
1078         /* select mode is either replace (deselect all, then add) or add/extend */
1079         // XXX this is currently only available for normal select only
1080         if (RNA_boolean_get(op->ptr, "extend_select"))
1081                 selectmode= SELECT_INVERT;
1082         else
1083                 selectmode= SELECT_REPLACE;
1084         
1085         /* figure out action to take */
1086         if (RNA_enum_get(op->ptr, "left_right")) {
1087                 /* select all keys on same side of current frame as mouse */
1088                 float x;
1089                 
1090                 UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, NULL);
1091                 if (x < CFRA)
1092                         RNA_int_set(op->ptr, "left_right", ACTKEYS_LRSEL_LEFT);
1093                 else    
1094                         RNA_int_set(op->ptr, "left_right", ACTKEYS_LRSEL_RIGHT);
1095                 
1096                 selectkeys_leftright(&ac, RNA_enum_get(op->ptr, "left_right"), selectmode);
1097         }
1098         else if (RNA_boolean_get(op->ptr, "column_select")) {
1099                 /* select all the keyframes that occur on the same frame as where the mouse clicked */
1100                 float x;
1101                 
1102                 /* figure out where (the frame) the mouse clicked, and set all keyframes in that frame */
1103                 UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, NULL);
1104                 mouse_columnselect_action_keys(&ac, x);
1105         }
1106         else {
1107                 /* select keyframe under mouse */
1108                 mouse_action_keys(&ac, mval, selectmode);
1109                 // XXX activate transform...
1110         }
1111         
1112         /* set notifier tha things have changed */
1113         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
1114         
1115         return OPERATOR_FINISHED;
1116 }
1117  
1118 void ACT_OT_keyframes_clickselect (wmOperatorType *ot)
1119 {
1120         PropertyRNA *prop;
1121         
1122         /* identifiers */
1123         ot->name= "Mouse Select Keys";
1124         ot->idname= "ACT_OT_keyframes_clickselect";
1125         
1126         /* api callbacks */
1127         ot->invoke= actkeys_clickselect_invoke;
1128         ot->poll= ED_operator_areaactive;
1129         
1130         /* id-props */
1131         // XXX should we make this into separate operators?
1132         prop= RNA_def_property(ot->srna, "left_right", PROP_ENUM, PROP_NONE); // ALTKEY
1133                 //RNA_def_property_enum_items(prop, prop_actkeys_clickselect_items);
1134         prop= RNA_def_property(ot->srna, "extend_select", PROP_BOOLEAN, PROP_NONE); // SHIFTKEY
1135         prop= RNA_def_property(ot->srna, "column_select", PROP_BOOLEAN, PROP_NONE); // CTRLKEY
1136 }
1137
1138 /* ************************************************************************** */