Animato: Various improvements
[blender.git] / source / blender / editors / animation / anim_channels.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_anim_types.h"
46 #include "DNA_action_types.h"
47 #include "DNA_armature_types.h"
48 #include "DNA_camera_types.h"
49 #include "DNA_curve_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 #include "DNA_world_types.h"
62
63 #include "RNA_access.h"
64 #include "RNA_define.h"
65
66 #include "BKE_action.h"
67 #include "BKE_depsgraph.h"
68 #include "BKE_ipo.h"
69 #include "BKE_key.h"
70 #include "BKE_material.h"
71 #include "BKE_object.h"
72 #include "BKE_context.h"
73 #include "BKE_utildefines.h"
74
75 #include "UI_interface.h"
76 #include "UI_resources.h"
77 #include "UI_view2d.h"
78
79 #include "ED_anim_api.h"
80 #include "ED_keyframes_edit.h" // XXX move the select modes out of there!
81 #include "ED_screen.h"
82 #include "ED_space_api.h"
83
84 #include "WM_api.h"
85 #include "WM_types.h"
86
87 /* ************************************************************************** */
88 /* CHANNELS API */
89
90 /* -------------------------- Internal Macros ------------------------------- */
91
92 /* set/clear/toggle macro 
93  *      - channel - channel with a 'flag' member that we're setting
94  *      - smode - 0=clear, 1=set, 2=toggle
95  *      - sflag - bitflag to set
96  */
97 #define ACHANNEL_SET_FLAG(channel, smode, sflag) \
98         { \
99                 if (smode == ACHANNEL_SETFLAG_TOGGLE)   (channel)->flag ^= (sflag); \
100                 else if (smode == ACHANNEL_SETFLAG_ADD) (channel)->flag |= (sflag); \
101                 else                                                                    (channel)->flag &= ~(sflag); \
102         }
103
104 /* -------------------------- Internal Tools -------------------------------- */
105
106 /* set the given Action Group to be the 'active' one in its Action */
107 static void action_set_active_agrp (bAction *act, bActionGroup *agrp)
108 {
109         bActionGroup *grp;
110         
111         /* sanity check */
112         if (act == NULL)
113                 return;
114                 
115         /* clear active flag on all others */
116         for (grp= act->groups.first; grp; grp= grp->next)
117                 grp->flag &= ~AGRP_ACTIVE;
118                 
119         /* set the given group to be the active one */
120         if (agrp)
121                 agrp->flag |= AGRP_ACTIVE;
122 }
123
124 /* -------------------------- Exposed API ----------------------------------- */
125
126 /* Set the given ActionChannel or ActionGroup as the active one in the given action
127  *      - data: should be bAction...
128  *      - datatype: should be ANIMCONT_ACTION 
129  *      - channel_data: bActionChannel or bActionGroup
130  *      - channel_type: eAnim_ChannelType
131  */
132 void ANIM_action_set_active_channel (void *data, short datatype, void *channel_data, short channel_type)
133 {
134         /* sanity checks */
135         if ((data == NULL) || (datatype != ANIMCONT_ACTION))
136                 return;
137                 
138         switch (channel_type) {
139                 case ANIMTYPE_GROUP:
140                         action_set_active_agrp((bAction *)data, (bActionGroup *)channel_data);
141                         break;
142         }
143 }
144
145 /* Deselect all animation channels 
146  *      - data: pointer to datatype, as contained in bAnimContext
147  *      - datatype: the type of data that 'data' represents (eAnimCont_Types)
148  *      - test: check if deselecting instead of selecting
149  *      - sel: eAnimChannels_SetFlag;
150  */
151 void ANIM_deselect_anim_channels (void *data, short datatype, short test, short sel)
152 {
153         ListBase anim_data = {NULL, NULL};
154         bAnimListElem *ale;
155         int filter;
156         
157         /* filter data */
158         filter= ANIMFILTER_VISIBLE;
159         ANIM_animdata_filter(NULL, &anim_data, filter, data, datatype);
160         
161         /* See if we should be selecting or deselecting */
162         if (test) {
163                 for (ale= anim_data.first; ale; ale= ale->next) {
164                         if (sel == 0) 
165                                 break;
166                         
167                         switch (ale->type) {
168                                 case ANIMTYPE_SCENE:
169                                         if (ale->flag & SCE_DS_SELECTED)
170                                                 sel= ACHANNEL_SETFLAG_CLEAR;
171                                         break;
172                                 case ANIMTYPE_OBJECT:
173                                         if (ale->flag & SELECT)
174                                                 sel= ACHANNEL_SETFLAG_CLEAR;
175                                         break;
176                                 case ANIMTYPE_FILLACTD:
177                                         if (ale->flag & ACT_SELECTED)
178                                                 sel= ACHANNEL_SETFLAG_CLEAR;
179                                         break;
180                                 case ANIMTYPE_GROUP:
181                                         if (ale->flag & AGRP_SELECTED)
182                                                 sel= ACHANNEL_SETFLAG_CLEAR;
183                                         break;
184                                 case ANIMTYPE_FCURVE:
185                                         if (ale->flag & FCURVE_SELECTED)
186                                                 sel= ACHANNEL_SETFLAG_CLEAR;
187                                         break;
188                         }
189                 }
190         }
191                 
192         /* Now set the flags */
193         for (ale= anim_data.first; ale; ale= ale->next) {
194                 switch (ale->type) {
195                         case ANIMTYPE_SCENE:
196                         {
197                                 Scene *scene= (Scene *)ale->data;
198                                 
199                                 ACHANNEL_SET_FLAG(scene, sel, SCE_DS_SELECTED);
200                         }
201                                 break;
202                         case ANIMTYPE_OBJECT:
203                         {
204                                 Base *base= (Base *)ale->data;
205                                 Object *ob= base->object;
206                                 
207                                 ACHANNEL_SET_FLAG(base, sel, SELECT);
208                                 ACHANNEL_SET_FLAG(ob, sel, SELECT);
209                         }
210                                 break;
211                         case ANIMTYPE_FILLACTD:
212                         {
213                                 bAction *act= (bAction *)ale->data;
214                                 
215                                 ACHANNEL_SET_FLAG(act, sel, ACT_SELECTED);
216                         }
217                                 break;
218                         case ANIMTYPE_GROUP:
219                         {
220                                 bActionGroup *agrp= (bActionGroup *)ale->data;
221                                 
222                                 ACHANNEL_SET_FLAG(agrp, sel, AGRP_SELECTED);
223                                 agrp->flag &= ~AGRP_ACTIVE;
224                         }
225                                 break;
226                         case ANIMTYPE_FCURVE:
227                         {
228                                 FCurve *fcu= (FCurve *)ale->data;
229                                 
230                                 ACHANNEL_SET_FLAG(fcu, sel, FCURVE_SELECTED);
231                                 fcu->flag &= ~FCURVE_ACTIVE;
232                         }
233                                 break;
234                 }
235         }
236         
237         /* Cleanup */
238         BLI_freelistN(&anim_data);
239 }
240
241 /* ************************************************************************** */
242 /* OPERATORS */
243
244 /* ****************** Rearrange Channels Operator ******************* */
245 /* This operator only works for Action Editor mode for now, as having it elsewhere makes things difficult */
246
247 #if 0 // XXX old animation system - needs to be updated for new system...
248
249 /* constants for channel rearranging */
250 /* WARNING: don't change exising ones without modifying rearrange func accordingly */
251 enum {
252         REARRANGE_ACTCHAN_TOP= -2,
253         REARRANGE_ACTCHAN_UP= -1,
254         REARRANGE_ACTCHAN_DOWN= 1,
255         REARRANGE_ACTCHAN_BOTTOM= 2
256 };
257
258 /* make sure all action-channels belong to a group (and clear action's list) */
259 static void split_groups_action_temp (bAction *act, bActionGroup *tgrp)
260 {
261         bActionChannel *achan;
262         bActionGroup *agrp;
263         
264         /* Separate action-channels into lists per group */
265         for (agrp= act->groups.first; agrp; agrp= agrp->next) {
266                 if (agrp->channels.first) {
267                         achan= agrp->channels.last;
268                         act->chanbase.first= achan->next;
269                         
270                         achan= agrp->channels.first;
271                         achan->prev= NULL;
272                         
273                         achan= agrp->channels.last;
274                         achan->next= NULL;
275                 }
276         }
277         
278         /* Initialise memory for temp-group */
279         memset(tgrp, 0, sizeof(bActionGroup));
280         tgrp->flag |= (AGRP_EXPANDED|AGRP_TEMP);
281         strcpy(tgrp->name, "#TempGroup");
282                 
283         /* Move any action-channels not already moved, to the temp group */
284         if (act->chanbase.first) {
285                 /* start of list */
286                 achan= act->chanbase.first;
287                 achan->prev= NULL;
288                 tgrp->channels.first= achan;
289                 act->chanbase.first= NULL;
290                 
291                 /* end of list */
292                 achan= act->chanbase.last;
293                 achan->next= NULL;
294                 tgrp->channels.last= achan;
295                 act->chanbase.last= NULL;
296         }
297         
298         /* Add temp-group to list */
299         BLI_addtail(&act->groups, tgrp);
300 }
301
302 /* link lists of channels that groups have */
303 static void join_groups_action_temp (bAction *act)
304 {
305         bActionGroup *agrp;
306         bActionChannel *achan;
307         
308         for (agrp= act->groups.first; agrp; agrp= agrp->next) {
309                 ListBase tempGroup;
310                 
311                 /* add list of channels to action's channels */
312                 tempGroup= agrp->channels;
313                 addlisttolist(&act->chanbase, &agrp->channels);
314                 agrp->channels= tempGroup;
315                 
316                 /* clear moved flag */
317                 agrp->flag &= ~AGRP_MOVED;
318                 
319                 /* if temp-group... remove from list (but don't free as it's on the stack!) */
320                 if (agrp->flag & AGRP_TEMP) {
321                         BLI_remlink(&act->groups, agrp);
322                         break;
323                 }
324         }
325         
326         /* clear "moved" flag from all achans */
327         for (achan= act->chanbase.first; achan; achan= achan->next) 
328                 achan->flag &= ~ACHAN_MOVED;
329 }
330
331
332 static short rearrange_actchannel_is_ok (Link *channel, short type)
333 {
334         if (type == ANIMTYPE_GROUP) {
335                 bActionGroup *agrp= (bActionGroup *)channel;
336                 
337                 if (SEL_AGRP(agrp) && !(agrp->flag & AGRP_MOVED))
338                         return 1;
339         }
340         else if (type == ANIMTYPE_ACHAN) {
341                 bActionChannel *achan= (bActionChannel *)channel;
342                 
343                 if (VISIBLE_ACHAN(achan) && SEL_ACHAN(achan) && !(achan->flag & ACHAN_MOVED))
344                         return 1;
345         }
346         
347         return 0;
348 }
349
350 static short rearrange_actchannel_after_ok (Link *channel, short type)
351 {
352         if (type == ANIMTYPE_GROUP) {
353                 bActionGroup *agrp= (bActionGroup *)channel;
354                 
355                 if (agrp->flag & AGRP_TEMP)
356                         return 0;
357         }
358         
359         return 1;
360 }
361
362
363 static short rearrange_actchannel_top (ListBase *list, Link *channel, short type)
364 {
365         if (rearrange_actchannel_is_ok(channel, type)) {
366                 /* take it out off the chain keep data */
367                 BLI_remlink(list, channel);
368                 
369                 /* make it first element */
370                 BLI_insertlinkbefore(list, list->first, channel);
371                 
372                 return 1;
373         }
374         
375         return 0;
376 }
377
378 static short rearrange_actchannel_up (ListBase *list, Link *channel, short type)
379 {
380         if (rearrange_actchannel_is_ok(channel, type)) {
381                 Link *prev= channel->prev;
382                 
383                 if (prev) {
384                         /* take it out off the chain keep data */
385                         BLI_remlink(list, channel);
386                         
387                         /* push it up */
388                         BLI_insertlinkbefore(list, prev, channel);
389                         
390                         return 1;
391                 }
392         }
393         
394         return 0;
395 }
396
397 static short rearrange_actchannel_down (ListBase *list, Link *channel, short type)
398 {
399         if (rearrange_actchannel_is_ok(channel, type)) {
400                 Link *next = (channel->next) ? channel->next->next : NULL;
401                 
402                 if (next) {
403                         /* take it out off the chain keep data */
404                         BLI_remlink(list, channel);
405                         
406                         /* move it down */
407                         BLI_insertlinkbefore(list, next, channel);
408                         
409                         return 1;
410                 }
411                 else if (rearrange_actchannel_after_ok(list->last, type)) {
412                         /* take it out off the chain keep data */
413                         BLI_remlink(list, channel);
414                         
415                         /* add at end */
416                         BLI_addtail(list, channel);
417                         
418                         return 1;
419                 }
420                 else {
421                         /* take it out off the chain keep data */
422                         BLI_remlink(list, channel);
423                         
424                         /* add just before end */
425                         BLI_insertlinkbefore(list, list->last, channel);
426                         
427                         return 1;
428                 }
429         }
430         
431         return 0;
432 }
433
434 static short rearrange_actchannel_bottom (ListBase *list, Link *channel, short type)
435 {
436         if (rearrange_actchannel_is_ok(channel, type)) {
437                 if (rearrange_actchannel_after_ok(list->last, type)) {
438                         /* take it out off the chain keep data */
439                         BLI_remlink(list, channel);
440                         
441                         /* add at end */
442                         BLI_addtail(list, channel);
443                         
444                         return 1;
445                 }
446         }
447         
448         return 0;
449 }
450
451
452 /* Change the order of action-channels 
453  *      mode: REARRANGE_ACTCHAN_*  
454  */
455 static void rearrange_action_channels (bAnimContext *ac, short mode)
456 {
457         bAction *act;
458         bActionChannel *achan, *chan;
459         bActionGroup *agrp, *grp;
460         bActionGroup tgrp;
461         
462         short (*rearrange_func)(ListBase *, Link *, short);
463         short do_channels = 1;
464         
465         /* Get the active action, exit if none are selected */
466         act= (bAction *)ac->data;
467         
468         /* exit if invalid mode */
469         switch (mode) {
470                 case REARRANGE_ACTCHAN_TOP:
471                         rearrange_func= rearrange_actchannel_top;
472                         break;
473                 case REARRANGE_ACTCHAN_UP:
474                         rearrange_func= rearrange_actchannel_up;
475                         break;
476                 case REARRANGE_ACTCHAN_DOWN:
477                         rearrange_func= rearrange_actchannel_down;
478                         break;
479                 case REARRANGE_ACTCHAN_BOTTOM:
480                         rearrange_func= rearrange_actchannel_bottom;
481                         break;
482                 default:
483                         return;
484         }
485         
486         /* make sure we're only operating with groups */
487         split_groups_action_temp(act, &tgrp);
488         
489         /* rearrange groups first (and then, only consider channels if the groups weren't moved) */
490         #define GET_FIRST(list) ((mode > 0) ? (list.first) : (list.last))
491         #define GET_NEXT(item) ((mode > 0) ? (item->next) : (item->prev))
492         
493         for (agrp= GET_FIRST(act->groups); agrp; agrp= grp) {
494                 /* Get next group to consider */
495                 grp= GET_NEXT(agrp);
496                 
497                 /* try to do group first */
498                 if (rearrange_func(&act->groups, (Link *)agrp, ANIMTYPE_GROUP)) {
499                         do_channels= 0;
500                         agrp->flag |= AGRP_MOVED;
501                 }
502         }
503         
504         if (do_channels) {
505                 for (agrp= GET_FIRST(act->groups); agrp; agrp= grp) {
506                         /* Get next group to consider */
507                         grp= GET_NEXT(agrp);
508                         
509                         /* only consider action-channels if they're visible (group expanded) */
510                         if (EXPANDED_AGRP(agrp)) {
511                                 for (achan= GET_FIRST(agrp->channels); achan; achan= chan) {
512                                         /* Get next channel to consider */
513                                         chan= GET_NEXT(achan);
514                                         
515                                         /* Try to do channel */
516                                         if (rearrange_func(&agrp->channels, (Link *)achan, ANIMTYPE_ACHAN))
517                                                 achan->flag |= ACHAN_MOVED;
518                                 }
519                         }
520                 }
521         }
522         #undef GET_FIRST
523         #undef GET_NEXT
524         
525         /* assemble lists into one list (and clear moved tags) */
526         join_groups_action_temp(act);
527 }
528
529 /* ------------------- */
530
531 static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
532 {
533         bAnimContext ac;
534         short mode;
535         
536         /* get editor data - only for Action Editor (for now) */
537         if (ANIM_animdata_get_context(C, &ac) == 0)
538                 return OPERATOR_CANCELLED;
539         if (ac.datatype != ANIMCONT_ACTION)
540                 return OPERATOR_PASS_THROUGH;
541                 
542         /* get mode, then rearrange channels */
543         mode= RNA_enum_get(op->ptr, "direction");
544         rearrange_action_channels(&ac, mode);
545         
546         /* set notifier tha things have changed */
547         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
548         
549         return OPERATOR_FINISHED;
550 }
551  
552
553 void ANIM_OT_channels_move_up (wmOperatorType *ot)
554 {
555         /* identifiers */
556         ot->name= "Move Channel(s) Up";
557         ot->idname= "ANIM_OT_channels_move_up";
558         
559         /* api callbacks */
560         ot->exec= animchannels_rearrange_exec;
561         ot->poll= ED_operator_areaactive;
562         
563         /* flags */
564         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
565         
566         /* props */
567         RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_UP, "Direction", "");
568 }
569
570 void ANIM_OT_channels_move_down (wmOperatorType *ot)
571 {
572         /* identifiers */
573         ot->name= "Move Channel(s) Down";
574         ot->idname= "ANIM_OT_channels_move_down";
575         
576         /* api callbacks */
577         ot->exec= animchannels_rearrange_exec;
578         ot->poll= ED_operator_areaactive;
579         
580         /* flags */
581         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
582         
583         /* props */
584         RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_DOWN, "Direction", "");
585 }
586
587 void ANIM_OT_channels_move_top (wmOperatorType *ot)
588 {
589         /* identifiers */
590         ot->name= "Move Channel(s) to Top";
591         ot->idname= "ANIM_OT_channels_move_to_top";
592         
593         /* api callbacks */
594         ot->exec= animchannels_rearrange_exec;
595         ot->poll= ED_operator_areaactive;
596         
597         /* flags */
598         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
599         
600         /* props */
601         RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_TOP, "Direction", "");
602 }
603
604 void ANIM_OT_channels_move_bottom (wmOperatorType *ot)
605 {
606         /* identifiers */
607         ot->name= "Move Channel(s) to Bottom";
608         ot->idname= "ANIM_OT_channels_move_to_bottom";
609         
610         /* api callbacks */
611         ot->exec= animchannels_rearrange_exec;
612         ot->poll= ED_operator_areaactive;
613         
614         /* flags */
615         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
616         
617         /* props */
618         RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_BOTTOM, "Direction", "");
619 }
620
621 #endif // XXX old animation system - needs to be updated for new system...
622
623
624 /* ******************** Toggle Channel Visibility Operator *********************** */
625
626 static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *op)
627 {
628         bAnimContext ac;
629         ListBase anim_data = {NULL, NULL};
630         bAnimListElem *ale;
631         int filter;
632         short vis= ACHANNEL_SETFLAG_ADD;
633         
634         /* get editor data */
635         if (ANIM_animdata_get_context(C, &ac) == 0)
636                 return OPERATOR_CANCELLED;
637                 
638         /* filter data */
639         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CURVESONLY);
640         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
641         
642         /* See if we should be making showing all selected or hiding */
643         for (ale= anim_data.first; ale; ale= ale->next) {
644                 if (vis == ACHANNEL_SETFLAG_CLEAR) 
645                         break;
646                 
647                 if (ale->flag & FCURVE_VISIBLE)
648                         vis= ACHANNEL_SETFLAG_CLEAR;
649         }
650                 
651         /* Now set the flags */
652         for (ale= anim_data.first; ale; ale= ale->next) {
653                 FCurve *fcu= (FCurve *)ale->data;
654                 ACHANNEL_SET_FLAG(fcu, vis, FCURVE_VISIBLE);
655         }
656         
657         /* cleanup */
658         BLI_freelistN(&anim_data);
659         
660         /* set notifier tha things have changed */
661         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
662         
663         return OPERATOR_FINISHED;
664 }
665  
666 void ANIM_OT_channels_visibility_toggle (wmOperatorType *ot)
667 {
668         /* identifiers */
669         ot->name= "Toggle Visibility";
670         ot->idname= "ANIM_OT_channels_visibility_toggle";
671         
672         /* api callbacks */
673         ot->exec= animchannels_visibility_toggle_exec;
674         ot->poll= ED_operator_ipo_active;
675         
676         /* flags */
677         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
678 }
679
680 /* ********************** Set Flags Operator *********************** */
681
682 enum {
683 //      ACHANNEL_SETTING_SELECT = 0,
684         ACHANNEL_SETTING_PROTECT = 1,
685         ACHANNEL_SETTING_MUTE,
686         ACHANNEL_SETTING_VISIBLE,
687 } eAnimChannel_Settings;
688
689 /* defines for setting animation-channel flags */
690 EnumPropertyItem prop_animchannel_setflag_types[] = {
691         {ACHANNEL_SETFLAG_CLEAR, "DISABLE", "Disable", ""},
692         {ACHANNEL_SETFLAG_ADD, "ENABLE", "Enable", ""},
693         {ACHANNEL_SETFLAG_TOGGLE, "TOGGLE", "Toggle", ""},
694         {0, NULL, NULL, NULL}
695 };
696
697 /* defines for set animation-channel settings */
698 EnumPropertyItem prop_animchannel_settings_types[] = {
699         {ACHANNEL_SETTING_PROTECT, "PROTECT", "Protect", ""},
700         {ACHANNEL_SETTING_MUTE, "MUTE", "Mute", ""},
701         {0, NULL, NULL, NULL}
702 };
703
704
705 /* ------------------- */
706
707 /* Set/clear a particular flag (setting) for all selected + visible channels 
708  *      setting: the setting to modify
709  *      mode: eAnimChannels_SetFlag
710  */
711 static void setflag_anim_channels (bAnimContext *ac, short setting, short mode)
712 {
713         ListBase anim_data = {NULL, NULL};
714         bAnimListElem *ale;
715         int filter;
716         
717         /* filter data */
718         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS | ANIMFILTER_SEL);
719         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
720         
721         /* affect selected channels */
722         for (ale= anim_data.first; ale; ale= ale->next) {
723                 switch (ale->type) {
724                         case ANIMTYPE_GROUP:
725                         {
726                                 bActionGroup *agrp= (bActionGroup *)ale->data;
727                                 
728                                 /* only 'protect' is available */
729                                 if (setting == ACHANNEL_SETTING_PROTECT) {
730                                         ACHANNEL_SET_FLAG(agrp, mode, AGRP_PROTECTED);
731                                 }
732                         }
733                                 break;
734                         case ANIMTYPE_FCURVE:
735                         {
736                                 FCurve *fcu= (FCurve *)ale->data;
737                                 
738                                 /* mute */
739                                 if (setting == ACHANNEL_SETTING_MUTE) {
740                                         ACHANNEL_SET_FLAG(fcu, mode, FCURVE_MUTED);
741                                 }
742                                 else if (setting == ACHANNEL_SETTING_PROTECT) {
743                                         ACHANNEL_SET_FLAG(fcu, mode, FCURVE_PROTECTED);
744                                 }
745                                 else if (setting == ACHANNEL_SETTING_VISIBLE) {
746                                         ACHANNEL_SET_FLAG(fcu, mode, FCURVE_VISIBLE);
747                                 }
748                         }
749                                 break;
750                         case ANIMTYPE_GPLAYER:
751                         {
752                                 bGPDlayer *gpl= (bGPDlayer *)ale->data;
753                                 
754                                 /* 'protect' and 'mute' */
755                                 if (setting == ACHANNEL_SETTING_MUTE) {
756                                         /* mute */
757                                         ACHANNEL_SET_FLAG(gpl, mode, GP_LAYER_HIDE);
758                                 }
759                                 else if (setting == ACHANNEL_SETTING_PROTECT) {
760                                         /* protected */
761                                         ACHANNEL_SET_FLAG(gpl, mode, GP_LAYER_LOCKED);
762                                 }
763                         }
764                                 break;
765                 }
766         }
767         
768         BLI_freelistN(&anim_data);
769 }
770
771 /* ------------------- */
772
773 static int animchannels_setflag_exec(bContext *C, wmOperator *op)
774 {
775         bAnimContext ac;
776         short mode, setting;
777         
778         /* get editor data */
779         if (ANIM_animdata_get_context(C, &ac) == 0)
780                 return OPERATOR_CANCELLED;
781                 
782         /* mode (eAnimChannels_SetFlag), setting (eAnimChannel_Settings) */
783         mode= RNA_enum_get(op->ptr, "mode");
784         setting= RNA_enum_get(op->ptr, "type");
785         
786         /* modify setting */
787         setflag_anim_channels(&ac, setting, mode);
788         
789         /* set notifier tha things have changed */
790         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
791         
792         return OPERATOR_FINISHED;
793 }
794
795
796 void ANIM_OT_channels_enable_setting (wmOperatorType *ot)
797 {
798         /* identifiers */
799         ot->name= "Enable Channel Setting";
800         ot->idname= "ANIM_OT_channels_enable_setting";
801         
802         /* api callbacks */
803         ot->invoke= WM_menu_invoke;
804         ot->exec= animchannels_setflag_exec;
805         ot->poll= ED_operator_areaactive;
806         
807         /* flags */
808         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
809         
810         /* props */
811                 /* flag-setting mode */
812         RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_ADD, "Mode", "");
813                 /* setting to set */
814         RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
815 }
816
817 void ANIM_OT_channels_disable_setting (wmOperatorType *ot)
818 {
819         /* identifiers */
820         ot->name= "Disable Channel Setting";
821         ot->idname= "ANIM_OT_channels_disable_setting";
822         
823         /* api callbacks */
824         ot->invoke= WM_menu_invoke;
825         ot->exec= animchannels_setflag_exec;
826         ot->poll= ED_operator_areaactive;
827         
828         /* flags */
829         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
830         
831         /* props */
832                 /* flag-setting mode */
833         RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_CLEAR, "Mode", "");
834                 /* setting to set */
835         RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
836 }
837
838 void ANIM_OT_channels_toggle_setting (wmOperatorType *ot)
839 {
840         /* identifiers */
841         ot->name= "Toggle Channel Setting";
842         ot->idname= "ANIM_OT_channels_toggle_setting";
843         
844         /* api callbacks */
845         ot->invoke= WM_menu_invoke;
846         ot->exec= animchannels_setflag_exec;
847         ot->poll= ED_operator_areaactive;
848         
849         /* flags */
850         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
851         
852         /* props */
853                 /* flag-setting mode */
854         RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", "");
855                 /* setting to set */
856         RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
857 }
858
859 /* ********************** Select All Operator *********************** */
860
861 static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
862 {
863         bAnimContext ac;
864         
865         /* get editor data */
866         if (ANIM_animdata_get_context(C, &ac) == 0)
867                 return OPERATOR_CANCELLED;
868                 
869         /* 'standard' behaviour - check if selected, then apply relevant selection */
870         if (RNA_boolean_get(op->ptr, "invert"))
871                 ANIM_deselect_anim_channels(ac.data, ac.datatype, 0, ACHANNEL_SETFLAG_TOGGLE);
872         else
873                 ANIM_deselect_anim_channels(ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_ADD);
874         
875         /* set notifier tha things have changed */
876         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
877         
878         return OPERATOR_FINISHED;
879 }
880  
881 void ANIM_OT_channels_deselectall (wmOperatorType *ot)
882 {
883         /* identifiers */
884         ot->name= "Select All";
885         ot->idname= "ANIM_OT_channels_deselectall";
886         
887         /* api callbacks */
888         ot->exec= animchannels_deselectall_exec;
889         ot->poll= ED_operator_areaactive;
890         
891         /* flags */
892         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
893         
894         /* props */
895         RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
896 }
897
898 /* ******************** Borderselect Operator *********************** */
899
900 static void borderselect_anim_channels (bAnimContext *ac, rcti *rect, short selectmode)
901 {
902         ListBase anim_data = {NULL, NULL};
903         bAnimListElem *ale;
904         int filter;
905         
906         View2D *v2d= &ac->ar->v2d;
907         rctf rectf;
908         float ymin=0, ymax=(float)(-ACHANNEL_HEIGHT);
909         
910         /* convert border-region to view coordinates */
911         UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin+2, &rectf.xmin, &rectf.ymin);
912         UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax-2, &rectf.xmax, &rectf.ymax);
913         
914         /* filter data */
915         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
916         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
917         
918         /* loop over data, doing border select */
919         for (ale= anim_data.first; ale; ale= ale->next) {
920                 ymin= ymax - ACHANNEL_STEP;
921                 
922                 /* if channel is within border-select region, alter it */
923                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
924                         /* only the following types can be selected */
925                         switch (ale->type) {
926                                 case ANIMTYPE_OBJECT: /* object */
927                                 {
928                                         Base *base= (Base *)ale->data;
929                                         Object *ob= base->object;
930                                         
931                                         ACHANNEL_SET_FLAG(base, selectmode, SELECT);
932                                         ACHANNEL_SET_FLAG(ob, selectmode, SELECT);
933                                 }
934                                         break;
935                                 case ANIMTYPE_GROUP: /* action group */
936                                 {
937                                         bActionGroup *agrp= (bActionGroup *)ale->data;
938                                         
939                                         ACHANNEL_SET_FLAG(agrp, selectmode, AGRP_SELECTED);
940                                         agrp->flag &= ~AGRP_ACTIVE;
941                                 }
942                                         break;
943                                 case ANIMTYPE_FCURVE: /* F-Curve channel */
944                                 {
945                                         FCurve *fcu = (FCurve *)ale->data;
946                                         
947                                         ACHANNEL_SET_FLAG(fcu, selectmode, FCURVE_SELECTED);
948                                 }
949                                         break;
950                                 case ANIMTYPE_GPLAYER: /* grease-pencil layer */
951                                 {
952                                         bGPDlayer *gpl = (bGPDlayer *)ale->data;
953                                         
954                                         ACHANNEL_SET_FLAG(gpl, selectmode, GP_LAYER_SELECT);
955                                 }
956                                         break;
957                         }
958                 }
959                 
960                 /* set minimum extent to be the maximum of the next channel */
961                 ymax= ymin;
962         }
963         
964         /* cleanup */
965         BLI_freelistN(&anim_data);
966 }
967
968 /* ------------------- */
969
970 static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
971 {
972         bAnimContext ac;
973         rcti rect;
974         short selectmode=0;
975         int event;
976         
977         /* get editor data */
978         if (ANIM_animdata_get_context(C, &ac) == 0)
979                 return OPERATOR_CANCELLED;
980         
981         /* get settings from operator */
982         rect.xmin= RNA_int_get(op->ptr, "xmin");
983         rect.ymin= RNA_int_get(op->ptr, "ymin");
984         rect.xmax= RNA_int_get(op->ptr, "xmax");
985         rect.ymax= RNA_int_get(op->ptr, "ymax");
986                 
987         event= RNA_int_get(op->ptr, "event_type");
988         if (event == LEFTMOUSE) // FIXME... hardcoded
989                 selectmode = ACHANNEL_SETFLAG_ADD;
990         else
991                 selectmode = ACHANNEL_SETFLAG_CLEAR;
992         
993         /* apply borderselect animation channels */
994         borderselect_anim_channels(&ac, &rect, selectmode);
995         
996         return OPERATOR_FINISHED;
997
998
999 void ANIM_OT_channels_borderselect(wmOperatorType *ot)
1000 {
1001         /* identifiers */
1002         ot->name= "Border Select";
1003         ot->idname= "ANIM_OT_channels_borderselect";
1004         
1005         /* api callbacks */
1006         ot->invoke= WM_border_select_invoke;
1007         ot->exec= animchannels_borderselect_exec;
1008         ot->modal= WM_border_select_modal;
1009         
1010         ot->poll= ED_operator_areaactive;
1011         
1012         /* flags */
1013         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1014         
1015         /* rna */
1016         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1017         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1018         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1019         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1020         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1021 }
1022
1023 /* ******************** Mouse-Click Operator *********************** */
1024 /* Depending on the channel that was clicked on, the mouse click will activate whichever
1025  * part of the channel is relevant.
1026  *
1027  * NOTE: eventually, this should probably be phased out when many of these things are replaced with buttons
1028  */
1029
1030 static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, short selectmode)
1031 {
1032         ListBase anim_data = {NULL, NULL};
1033         bAnimListElem *ale;
1034         int filter;
1035         
1036         /* get the channel that was clicked on */
1037                 /* filter channels */
1038         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
1039         filter= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1040         
1041                 /* get channel from index */
1042         ale= BLI_findlink(&anim_data, channel_index);
1043         if (ale == NULL) {
1044                 /* channel not found */
1045                 printf("Error: animation channel (index = %d) not found in mouse_anim_channels() \n", channel_index);
1046                 
1047                 BLI_freelistN(&anim_data);
1048                 return;
1049         }
1050         
1051         /* selectmode -1 is a special case for ActionGroups only, which selects all of the channels underneath it only... */
1052         // TODO: should this feature be extended to work with other channel types too?
1053         if ((selectmode == -1) && (ale->type != ANIMTYPE_GROUP)) {
1054                 /* normal channels should not behave normally in this case */
1055                 BLI_freelistN(&anim_data);
1056                 return;
1057         }
1058         
1059         /* action to take depends on what channel we've got */
1060         switch (ale->type) {
1061                 case ANIMTYPE_SCENE:
1062                 {
1063                         Scene *sce= (Scene *)ale->data;
1064                         
1065                         if (x < 16) {
1066                                 /* toggle expand */
1067                                 sce->flag ^= SCE_DS_COLLAPSED;
1068                         }
1069                         else {
1070                                 /* set selection status */
1071                                 if (selectmode == SELECT_INVERT) {
1072                                         /* swap select */
1073                                         sce->flag ^= SCE_DS_SELECTED;
1074                                 }
1075                                 else {
1076                                         sce->flag |= SCE_DS_SELECTED;
1077                                 }
1078                         }
1079                 }
1080                         break;
1081                 case ANIMTYPE_OBJECT:
1082                 {
1083                         bDopeSheet *ads= (bDopeSheet *)ac->data;
1084                         Scene *sce= (Scene *)ads->source;
1085                         Base *base= (Base *)ale->data;
1086                         Object *ob= base->object;
1087                         
1088                         if (x < 16) {
1089                                 /* toggle expand */
1090                                 ob->nlaflag ^= OB_ADS_COLLAPSED; // XXX 
1091                         }
1092                         else {
1093                                 /* set selection status */
1094                                 if (selectmode == SELECT_INVERT) {
1095                                         /* swap select */
1096                                         base->flag ^= SELECT;
1097                                         ob->flag= base->flag;
1098                                 }
1099                                 else {
1100                                         Base *b;
1101                                         
1102                                         /* deleselect all */
1103                                         for (b= sce->base.first; b; b= b->next) {
1104                                                 b->flag &= ~SELECT;
1105                                                 b->object->flag= b->flag;
1106                                         }
1107                                         
1108                                         /* select object now */
1109                                         base->flag |= SELECT;
1110                                         ob->flag |= SELECT;
1111                                 }
1112                                 
1113                                 /* xxx should be ED_base_object_activate(), but we need context pointer for that... */
1114                                 //set_active_base(base);
1115                         }
1116                 }
1117                         break;
1118                 case ANIMTYPE_FILLACTD:
1119                 {
1120                         bAction *act= (bAction *)ale->data;
1121                         act->flag ^= ACT_COLLAPSED;
1122                 }
1123                         break;
1124                 case ANIMTYPE_FILLDRIVERS:
1125                 {
1126                         AnimData *adt= (AnimData* )ale->data;
1127                         adt->flag ^= ADT_DRIVERS_COLLAPSED;
1128                 }
1129                         break;
1130                 case ANIMTYPE_FILLMATD:
1131                 {
1132                         Object *ob= (Object *)ale->data;
1133                         ob->nlaflag ^= OB_ADS_SHOWMATS; // XXX 
1134                 }
1135                         break;
1136                                 
1137                 case ANIMTYPE_DSMAT:
1138                 {
1139                         Material *ma= (Material *)ale->data;
1140                         ma->flag ^= MA_DS_EXPAND;
1141                 }
1142                         break;
1143                 case ANIMTYPE_DSLAM:
1144                 {
1145                         Lamp *la= (Lamp *)ale->data;
1146                         la->flag ^= LA_DS_EXPAND;
1147                 }
1148                         break;
1149                 case ANIMTYPE_DSCAM:
1150                 {
1151                         Camera *ca= (Camera *)ale->data;
1152                         ca->flag ^= CAM_DS_EXPAND;
1153                 }
1154                         break;
1155                 case ANIMTYPE_DSCUR:
1156                 {
1157                         Curve *cu= (Curve *)ale->data;
1158                         cu->flag ^= CU_DS_EXPAND;
1159                 }
1160                         break;
1161                 case ANIMTYPE_DSSKEY:
1162                 {
1163                         Key *key= (Key *)ale->data;
1164                         key->flag ^= KEYBLOCK_DS_EXPAND;
1165                 }
1166                         break;
1167                 case ANIMTYPE_DSWOR:
1168                 {
1169                         World *wo= (World *)ale->data;
1170                         wo->flag ^= WO_DS_EXPAND;
1171                 }
1172                         break;
1173                         
1174                 case ANIMTYPE_GROUP: 
1175                 {
1176                         bActionGroup *agrp= (bActionGroup *)ale->data;
1177                         short offset= (ELEM3(ac->datatype, ANIMCONT_DOPESHEET, ANIMCONT_FCURVES, ANIMCONT_DRIVERS))? 18 : 0;
1178                         
1179                         if ((x < (offset+17)) && (agrp->channels.first)) {
1180                                 /* toggle expand */
1181                                 agrp->flag ^= AGRP_EXPANDED;
1182                         }
1183                         else if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
1184                                 /* toggle protection/locking */
1185                                 agrp->flag ^= AGRP_PROTECTED;
1186                         }
1187                         else {
1188                                 /* select/deselect group */
1189                                 if (selectmode == SELECT_INVERT) {
1190                                         /* inverse selection status of this group only */
1191                                         agrp->flag ^= AGRP_SELECTED;
1192                                 }
1193                                 else if (selectmode == -1) {
1194                                         /* select all in group (and deselect everthing else) */ 
1195                                         bActionChannel *achan;
1196                                         
1197                                         /* deselect all other channels */
1198                                         ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1199                                         
1200                                         /* only select channels in group and group itself */
1201                                         for (achan= agrp->channels.first; achan && achan->grp==agrp; achan= achan->next)
1202                                                 achan->flag |= ACHAN_SELECTED;
1203                                         agrp->flag |= AGRP_SELECTED;                                    
1204                                 }
1205                                 else {
1206                                         /* select group by itself */
1207                                         ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1208                                         agrp->flag |= AGRP_SELECTED;
1209                                 }
1210                                 
1211                                 /* if group is selected now, and we're in Action Editor mode (so that we have pointer to active action),
1212                                  * we can make this group the 'active' one in that action
1213                                  */
1214                                 if ((agrp->flag & AGRP_SELECTED) && (ac->datatype == ANIMCONT_ACTION))
1215                                         action_set_active_agrp((bAction *)ac->data, agrp);
1216                         }
1217                 }
1218                         break;
1219                 case ANIMTYPE_FCURVE: 
1220                 {
1221                         FCurve *fcu= (FCurve *)ale->data;
1222                         short offset= (ac->datatype != ANIMCONT_ACTION)? 18 : 0;
1223                         
1224                         if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
1225                                 /* toggle protection */
1226                                 fcu->flag ^= FCURVE_PROTECTED;
1227                         }
1228                         else if (x >= (ACHANNEL_NAMEWIDTH-2*ACHANNEL_BUTTON_WIDTH)) {
1229                                 /* toggle mute */
1230                                 fcu->flag ^= FCURVE_MUTED;
1231                         }
1232                         else if ((x < (offset+17)) && (ac->spacetype==SPACE_IPO)) {
1233                                 /* toggle visibility */
1234                                 // XXX this is supposed to be button before name, though this sometimes fails
1235                                 fcu->flag ^= FCURVE_VISIBLE;
1236                         }
1237                         else {
1238                                 /* select/deselect */
1239                                 fcu->flag ^= FCURVE_SELECTED;
1240                                 
1241                                 if (fcu->flag & FCURVE_SELECTED)
1242                                         fcu->flag |= FCURVE_ACTIVE;
1243                                 else
1244                                         fcu->flag &= ~FCURVE_ACTIVE;
1245                         }
1246                 }
1247                         break;
1248                 case ANIMTYPE_GPDATABLOCK:
1249                 {
1250                         bGPdata *gpd= (bGPdata *)ale->data;
1251                         
1252                         /* toggle expand */
1253                         gpd->flag ^= GP_DATA_EXPAND;
1254                 }
1255                         break;
1256                 case ANIMTYPE_GPLAYER:
1257                 {
1258 #if 0 // XXX future of this is unclear
1259                         bGPdata *gpd= (bGPdata *)ale->owner;
1260                         bGPDlayer *gpl= (bGPDlayer *)ale->data;
1261                         
1262                         if (x >= (ACHANNEL_NAMEWIDTH-16)) {
1263                                 /* toggle lock */
1264                                 gpl->flag ^= GP_LAYER_LOCKED;
1265                         }
1266                         else if (x >= (ACHANNEL_NAMEWIDTH-32)) {
1267                                 /* toggle hide */
1268                                 gpl->flag ^= GP_LAYER_HIDE;
1269                         }
1270                         else {
1271                                 /* select/deselect */
1272                                 //if (G.qual & LR_SHIFTKEY) {
1273                                         //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
1274                                 //}
1275                                 //else {
1276                                         //deselect_gpencil_layers(data, 0);
1277                                         //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
1278                                 //}
1279                         }
1280 #endif // XXX future of this is unclear
1281                 }
1282                         break;
1283                 case ANIMTYPE_SHAPEKEY:
1284                         /* TODO: shapekey channels cannot be selected atm... */
1285                         break;
1286                 default:
1287                         printf("Error: Invalid channel type in mouse_anim_channels() \n");
1288         }
1289         
1290         /* free channels */
1291         BLI_freelistN(&anim_data);
1292 }
1293
1294 /* ------------------- */
1295
1296 /* handle clicking */
1297 static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event)
1298 {
1299         bAnimContext ac;
1300         Scene *scene;
1301         ARegion *ar;
1302         View2D *v2d;
1303         int mval[2], channel_index;
1304         short selectmode;
1305         float x, y;
1306         
1307         
1308         /* get editor data */
1309         if (ANIM_animdata_get_context(C, &ac) == 0)
1310                 return OPERATOR_CANCELLED;
1311                 
1312         /* get useful pointers from animation context data */
1313         scene= ac.scene;
1314         ar= ac.ar;
1315         v2d= &ar->v2d;
1316         
1317         /* get mouse coordinates (in region coordinates) */
1318         mval[0]= (event->x - ar->winrct.xmin);
1319         mval[1]= (event->y - ar->winrct.ymin);
1320         
1321         /* select mode is either replace (deselect all, then add) or add/extend */
1322         if (RNA_boolean_get(op->ptr, "extend_select"))
1323                 selectmode= SELECT_INVERT;
1324         else if (RNA_boolean_get(op->ptr, "select_children_only"))
1325                 selectmode= -1; /* this is a bit of a special case for ActionGroups only... should it be removed or extended to all instead? */
1326         else
1327                 selectmode= SELECT_REPLACE;
1328         
1329         /* figure out which channel user clicked in 
1330          * Note: although channels technically start at y= ACHANNEL_FIRST, we need to adjust by half a channel's height
1331          *              so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
1332          *              ACHANNEL_HEIGHT_HALF.
1333          */
1334         UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
1335         UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
1336         
1337         /* handle mouse-click in the relevant channel then */
1338         mouse_anim_channels(&ac, x, channel_index, selectmode);
1339         
1340         /* set notifier tha things have changed */
1341         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
1342         
1343         return OPERATOR_FINISHED;
1344 }
1345  
1346 void ANIM_OT_channels_mouseclick (wmOperatorType *ot)
1347 {
1348         /* identifiers */
1349         ot->name= "Mouse Click on Channels";
1350         ot->idname= "ANIM_OT_channels_mouseclick";
1351         
1352         /* api callbacks */
1353         ot->invoke= animchannels_mouseclick_invoke;
1354         ot->poll= ED_operator_areaactive;
1355         
1356         /* flags */
1357         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1358         
1359         /* id-props */
1360         RNA_def_boolean(ot->srna, "extend_select", 0, "Extend Select", ""); // SHIFTKEY
1361         RNA_def_boolean(ot->srna, "select_children_only", 0, "Select Children Only", ""); // CTRLKEY|SHIFTKEY
1362 }
1363
1364 /* ************************************************************************** */
1365 /* Operator Registration */
1366
1367 void ED_operatortypes_animchannels(void)
1368 {
1369         WM_operatortype_append(ANIM_OT_channels_deselectall);
1370         WM_operatortype_append(ANIM_OT_channels_borderselect);
1371         WM_operatortype_append(ANIM_OT_channels_mouseclick);
1372         
1373         WM_operatortype_append(ANIM_OT_channels_enable_setting);
1374         WM_operatortype_append(ANIM_OT_channels_disable_setting);
1375         WM_operatortype_append(ANIM_OT_channels_toggle_setting);
1376         
1377                 // XXX these need to be updated for new system... todo...
1378         //WM_operatortype_append(ANIM_OT_channels_move_up);
1379         //WM_operatortype_append(ANIM_OT_channels_move_down);
1380         //WM_operatortype_append(ANIM_OT_channels_move_top);
1381         //WM_operatortype_append(ANIM_OT_channels_move_bottom);
1382         
1383         WM_operatortype_append(ANIM_OT_channels_visibility_toggle);
1384 }
1385
1386 void ED_keymap_animchannels(wmWindowManager *wm)
1387 {
1388         ListBase *keymap = WM_keymap_listbase(wm, "Animation_Channels", 0, 0);
1389         
1390         /* selection */
1391                 /* click-select */
1392                 // XXX for now, only leftmouse.... 
1393         WM_keymap_add_item(keymap, "ANIM_OT_channels_mouseclick", LEFTMOUSE, KM_PRESS, 0, 0);
1394         RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_mouseclick", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend_select", 1);
1395         RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_mouseclick", LEFTMOUSE, KM_PRESS, KM_CTRL|KM_SHIFT, 0)->ptr, "select_children_only", 1);
1396         
1397                 /* deselect all */
1398         WM_keymap_add_item(keymap, "ANIM_OT_channels_deselectall", AKEY, KM_PRESS, 0, 0);
1399         RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_deselectall", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
1400         
1401                 /* borderselect */
1402         WM_keymap_add_item(keymap, "ANIM_OT_channels_borderselect", BKEY, KM_PRESS, 0, 0);
1403         
1404         /* settings */
1405         WM_keymap_add_item(keymap, "ANIM_OT_channels_toggle_setting", WKEY, KM_PRESS, KM_SHIFT, 0);
1406         WM_keymap_add_item(keymap, "ANIM_OT_channels_enable_setting", WKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
1407         WM_keymap_add_item(keymap, "ANIM_OT_channels_disable_setting", WKEY, KM_PRESS, KM_ALT, 0);
1408         
1409         /* rearranging - actions only */
1410         //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_up", PAGEUPKEY, KM_PRESS, KM_SHIFT, 0);
1411         //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_down", PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0);
1412         //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_to_top", PAGEUPKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
1413         //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_to_bottom", PAGEDOWNKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
1414         
1415         /* Graph Editor only */
1416         WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_toggle", VKEY, KM_PRESS, 0, 0);
1417 }
1418
1419 /* ************************************************************************** */