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