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