Animation Editors: Added Tab-Key to toggle editability of selected 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 } eAnimChannel_Settings;
699
700 /* defines for setting animation-channel flags */
701 EnumPropertyItem prop_animchannel_setflag_types[] = {
702         {ACHANNEL_SETFLAG_CLEAR, "DISABLE", "Disable", ""},
703         {ACHANNEL_SETFLAG_ADD, "ENABLE", "Enable", ""},
704         {ACHANNEL_SETFLAG_TOGGLE, "TOGGLE", "Toggle", ""},
705         {0, NULL, NULL, NULL}
706 };
707
708 /* defines for set animation-channel settings */
709 EnumPropertyItem prop_animchannel_settings_types[] = {
710         {ACHANNEL_SETTING_PROTECT, "PROTECT", "Protect", ""},
711         {ACHANNEL_SETTING_MUTE, "MUTE", "Mute", ""},
712         {0, NULL, NULL, NULL}
713 };
714
715
716 /* ------------------- */
717
718 /* Set/clear a particular flag (setting) for all selected + visible channels 
719  *      setting: the setting to modify
720  *      mode: eAnimChannels_SetFlag
721  */
722 static void setflag_anim_channels (bAnimContext *ac, short setting, short mode)
723 {
724         ListBase anim_data = {NULL, NULL};
725         bAnimListElem *ale;
726         int filter;
727         
728         /* filter data */
729         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS | ANIMFILTER_SEL);
730         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
731         
732         /* affect selected channels */
733         for (ale= anim_data.first; ale; ale= ale->next) {
734                 switch (ale->type) {
735                         case ANIMTYPE_GROUP:
736                         {
737                                 bActionGroup *agrp= (bActionGroup *)ale->data;
738                                 
739                                 /* only 'protect' is available */
740                                 if (setting == ACHANNEL_SETTING_PROTECT) {
741                                         ACHANNEL_SET_FLAG(agrp, mode, AGRP_PROTECTED);
742                                 }
743                         }
744                                 break;
745                         case ANIMTYPE_FCURVE:
746                         {
747                                 FCurve *fcu= (FCurve *)ale->data;
748                                 
749                                 /* mute */
750                                 if (setting == ACHANNEL_SETTING_MUTE) {
751                                         ACHANNEL_SET_FLAG(fcu, mode, FCURVE_MUTED);
752                                 }
753                                 else if (setting == ACHANNEL_SETTING_PROTECT) {
754                                         ACHANNEL_SET_FLAG(fcu, mode, FCURVE_PROTECTED);
755                                 }
756                                 else if (setting == ACHANNEL_SETTING_VISIBLE) {
757                                         ACHANNEL_SET_FLAG(fcu, mode, FCURVE_VISIBLE);
758                                 }
759                         }
760                                 break;
761                         case ANIMTYPE_GPLAYER:
762                         {
763                                 bGPDlayer *gpl= (bGPDlayer *)ale->data;
764                                 
765                                 /* 'protect' and 'mute' */
766                                 if (setting == ACHANNEL_SETTING_MUTE) {
767                                         /* mute */
768                                         ACHANNEL_SET_FLAG(gpl, mode, GP_LAYER_HIDE);
769                                 }
770                                 else if (setting == ACHANNEL_SETTING_PROTECT) {
771                                         /* protected */
772                                         ACHANNEL_SET_FLAG(gpl, mode, GP_LAYER_LOCKED);
773                                 }
774                         }
775                                 break;
776                 }
777         }
778         
779         BLI_freelistN(&anim_data);
780 }
781
782 /* ------------------- */
783
784 static int animchannels_setflag_exec(bContext *C, wmOperator *op)
785 {
786         bAnimContext ac;
787         short mode, setting;
788         
789         /* get editor data */
790         if (ANIM_animdata_get_context(C, &ac) == 0)
791                 return OPERATOR_CANCELLED;
792                 
793         /* mode (eAnimChannels_SetFlag), setting (eAnimChannel_Settings) */
794         mode= RNA_enum_get(op->ptr, "mode");
795         setting= RNA_enum_get(op->ptr, "type");
796         
797         /* modify setting */
798         setflag_anim_channels(&ac, setting, mode);
799         
800         /* set notifier tha things have changed */
801         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
802         
803         return OPERATOR_FINISHED;
804 }
805
806
807 void ANIM_OT_channels_enable_setting (wmOperatorType *ot)
808 {
809         /* identifiers */
810         ot->name= "Enable Channel Setting";
811         ot->idname= "ANIM_OT_channels_enable_setting";
812         
813         /* api callbacks */
814         ot->invoke= WM_menu_invoke;
815         ot->exec= animchannels_setflag_exec;
816         ot->poll= ED_operator_areaactive;
817         
818         /* flags */
819         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
820         
821         /* props */
822                 /* flag-setting mode */
823         RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_ADD, "Mode", "");
824                 /* setting to set */
825         RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
826 }
827
828 void ANIM_OT_channels_disable_setting (wmOperatorType *ot)
829 {
830         /* identifiers */
831         ot->name= "Disable Channel Setting";
832         ot->idname= "ANIM_OT_channels_disable_setting";
833         
834         /* api callbacks */
835         ot->invoke= WM_menu_invoke;
836         ot->exec= animchannels_setflag_exec;
837         ot->poll= ED_operator_areaactive;
838         
839         /* flags */
840         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
841         
842         /* props */
843                 /* flag-setting mode */
844         RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_CLEAR, "Mode", "");
845                 /* setting to set */
846         RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
847 }
848
849 void ANIM_OT_channels_toggle_setting (wmOperatorType *ot)
850 {
851         /* identifiers */
852         ot->name= "Toggle Channel Setting";
853         ot->idname= "ANIM_OT_channels_toggle_setting";
854         
855         /* api callbacks */
856         ot->invoke= WM_menu_invoke;
857         ot->exec= animchannels_setflag_exec;
858         ot->poll= ED_operator_areaactive;
859         
860         /* flags */
861         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
862         
863         /* props */
864                 /* flag-setting mode */
865         RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", "");
866                 /* setting to set */
867         RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
868 }
869
870 // XXX currently, this is a separate operator, but perhaps we could in future specify in keymaps whether to call invoke or exec?
871 void ANIM_OT_channels_toggle_editable (wmOperatorType *ot)
872 {
873         /* identifiers */
874         ot->name= "Toggle Channel Editability";
875         ot->idname= "ANIM_OT_channels_toggle_editable";
876         
877         /* api callbacks */
878         ot->exec= animchannels_setflag_exec;
879         ot->poll= ED_operator_areaactive;
880         
881         /* flags */
882         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
883         
884         /* props */
885                 /* flag-setting mode */
886         RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", "");
887                 /* setting to set */
888         RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, ACHANNEL_SETTING_PROTECT, "Type", "");
889 }
890
891 /* ********************** Select All Operator *********************** */
892
893 static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
894 {
895         bAnimContext ac;
896         
897         /* get editor data */
898         if (ANIM_animdata_get_context(C, &ac) == 0)
899                 return OPERATOR_CANCELLED;
900                 
901         /* 'standard' behaviour - check if selected, then apply relevant selection */
902         if (RNA_boolean_get(op->ptr, "invert"))
903                 ANIM_deselect_anim_channels(ac.data, ac.datatype, 0, ACHANNEL_SETFLAG_TOGGLE);
904         else
905                 ANIM_deselect_anim_channels(ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_ADD);
906         
907         /* set notifier tha things have changed */
908         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
909         
910         return OPERATOR_FINISHED;
911 }
912  
913 void ANIM_OT_channels_deselectall (wmOperatorType *ot)
914 {
915         /* identifiers */
916         ot->name= "Select All";
917         ot->idname= "ANIM_OT_channels_deselectall";
918         
919         /* api callbacks */
920         ot->exec= animchannels_deselectall_exec;
921         ot->poll= ED_operator_areaactive;
922         
923         /* flags */
924         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
925         
926         /* props */
927         RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
928 }
929
930 /* ******************** Borderselect Operator *********************** */
931
932 static void borderselect_anim_channels (bAnimContext *ac, rcti *rect, short selectmode)
933 {
934         ListBase anim_data = {NULL, NULL};
935         bAnimListElem *ale;
936         int filter;
937         
938         View2D *v2d= &ac->ar->v2d;
939         rctf rectf;
940         float ymin=0, ymax=(float)(-ACHANNEL_HEIGHT);
941         
942         /* convert border-region to view coordinates */
943         UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin+2, &rectf.xmin, &rectf.ymin);
944         UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax-2, &rectf.xmax, &rectf.ymax);
945         
946         /* filter data */
947         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
948         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
949         
950         /* loop over data, doing border select */
951         for (ale= anim_data.first; ale; ale= ale->next) {
952                 ymin= ymax - ACHANNEL_STEP;
953                 
954                 /* if channel is within border-select region, alter it */
955                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
956                         /* only the following types can be selected */
957                         switch (ale->type) {
958                                 case ANIMTYPE_OBJECT: /* object */
959                                 {
960                                         Base *base= (Base *)ale->data;
961                                         Object *ob= base->object;
962                                         
963                                         ACHANNEL_SET_FLAG(base, selectmode, SELECT);
964                                         ACHANNEL_SET_FLAG(ob, selectmode, SELECT);
965                                 }
966                                         break;
967                                 case ANIMTYPE_GROUP: /* action group */
968                                 {
969                                         bActionGroup *agrp= (bActionGroup *)ale->data;
970                                         
971                                         ACHANNEL_SET_FLAG(agrp, selectmode, AGRP_SELECTED);
972                                         agrp->flag &= ~AGRP_ACTIVE;
973                                 }
974                                         break;
975                                 case ANIMTYPE_FCURVE: /* F-Curve channel */
976                                 {
977                                         FCurve *fcu = (FCurve *)ale->data;
978                                         
979                                         ACHANNEL_SET_FLAG(fcu, selectmode, FCURVE_SELECTED);
980                                 }
981                                         break;
982                                 case ANIMTYPE_GPLAYER: /* grease-pencil layer */
983                                 {
984                                         bGPDlayer *gpl = (bGPDlayer *)ale->data;
985                                         
986                                         ACHANNEL_SET_FLAG(gpl, selectmode, GP_LAYER_SELECT);
987                                 }
988                                         break;
989                         }
990                 }
991                 
992                 /* set minimum extent to be the maximum of the next channel */
993                 ymax= ymin;
994         }
995         
996         /* cleanup */
997         BLI_freelistN(&anim_data);
998 }
999
1000 /* ------------------- */
1001
1002 static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
1003 {
1004         bAnimContext ac;
1005         rcti rect;
1006         short selectmode=0;
1007         int event;
1008         
1009         /* get editor data */
1010         if (ANIM_animdata_get_context(C, &ac) == 0)
1011                 return OPERATOR_CANCELLED;
1012         
1013         /* get settings from operator */
1014         rect.xmin= RNA_int_get(op->ptr, "xmin");
1015         rect.ymin= RNA_int_get(op->ptr, "ymin");
1016         rect.xmax= RNA_int_get(op->ptr, "xmax");
1017         rect.ymax= RNA_int_get(op->ptr, "ymax");
1018                 
1019         event= RNA_int_get(op->ptr, "event_type");
1020         if (event == LEFTMOUSE) // FIXME... hardcoded
1021                 selectmode = ACHANNEL_SETFLAG_ADD;
1022         else
1023                 selectmode = ACHANNEL_SETFLAG_CLEAR;
1024         
1025         /* apply borderselect animation channels */
1026         borderselect_anim_channels(&ac, &rect, selectmode);
1027         
1028         return OPERATOR_FINISHED;
1029
1030
1031 void ANIM_OT_channels_borderselect(wmOperatorType *ot)
1032 {
1033         /* identifiers */
1034         ot->name= "Border Select";
1035         ot->idname= "ANIM_OT_channels_borderselect";
1036         
1037         /* api callbacks */
1038         ot->invoke= WM_border_select_invoke;
1039         ot->exec= animchannels_borderselect_exec;
1040         ot->modal= WM_border_select_modal;
1041         
1042         ot->poll= ED_operator_areaactive;
1043         
1044         /* flags */
1045         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1046         
1047         /* rna */
1048         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1049         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1050         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1051         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1052         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1053 }
1054
1055 /* ******************** Mouse-Click Operator *********************** */
1056 /* Depending on the channel that was clicked on, the mouse click will activate whichever
1057  * part of the channel is relevant.
1058  *
1059  * NOTE: eventually, this should probably be phased out when many of these things are replaced with buttons
1060  */
1061
1062 static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, short selectmode)
1063 {
1064         ListBase anim_data = {NULL, NULL};
1065         bAnimListElem *ale;
1066         int filter;
1067         
1068         /* get the channel that was clicked on */
1069                 /* filter channels */
1070         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
1071         filter= ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1072         
1073                 /* get channel from index */
1074         ale= BLI_findlink(&anim_data, channel_index);
1075         if (ale == NULL) {
1076                 /* channel not found */
1077                 printf("Error: animation channel (index = %d) not found in mouse_anim_channels() \n", channel_index);
1078                 
1079                 BLI_freelistN(&anim_data);
1080                 return;
1081         }
1082         
1083         /* selectmode -1 is a special case for ActionGroups only, which selects all of the channels underneath it only... */
1084         // TODO: should this feature be extended to work with other channel types too?
1085         if ((selectmode == -1) && (ale->type != ANIMTYPE_GROUP)) {
1086                 /* normal channels should not behave normally in this case */
1087                 BLI_freelistN(&anim_data);
1088                 return;
1089         }
1090         
1091         /* action to take depends on what channel we've got */
1092         switch (ale->type) {
1093                 case ANIMTYPE_SCENE:
1094                 {
1095                         Scene *sce= (Scene *)ale->data;
1096                         
1097                         if (x < 16) {
1098                                 /* toggle expand */
1099                                 sce->flag ^= SCE_DS_COLLAPSED;
1100                         }
1101                         else {
1102                                 /* set selection status */
1103                                 if (selectmode == SELECT_INVERT) {
1104                                         /* swap select */
1105                                         sce->flag ^= SCE_DS_SELECTED;
1106                                 }
1107                                 else {
1108                                         sce->flag |= SCE_DS_SELECTED;
1109                                 }
1110                         }
1111                 }
1112                         break;
1113                 case ANIMTYPE_OBJECT:
1114                 {
1115                         bDopeSheet *ads= (bDopeSheet *)ac->data;
1116                         Scene *sce= (Scene *)ads->source;
1117                         Base *base= (Base *)ale->data;
1118                         Object *ob= base->object;
1119                         
1120                         if (x < 16) {
1121                                 /* toggle expand */
1122                                 ob->nlaflag ^= OB_ADS_COLLAPSED; // XXX 
1123                         }
1124                         else {
1125                                 /* set selection status */
1126                                 if (selectmode == SELECT_INVERT) {
1127                                         /* swap select */
1128                                         base->flag ^= SELECT;
1129                                         ob->flag= base->flag;
1130                                 }
1131                                 else {
1132                                         Base *b;
1133                                         
1134                                         /* deleselect all */
1135                                         for (b= sce->base.first; b; b= b->next) {
1136                                                 b->flag &= ~SELECT;
1137                                                 b->object->flag= b->flag;
1138                                         }
1139                                         
1140                                         /* select object now */
1141                                         base->flag |= SELECT;
1142                                         ob->flag |= SELECT;
1143                                 }
1144                                 
1145                                 /* xxx should be ED_base_object_activate(), but we need context pointer for that... */
1146                                 //set_active_base(base);
1147                         }
1148                 }
1149                         break;
1150                 case ANIMTYPE_FILLACTD:
1151                 {
1152                         bAction *act= (bAction *)ale->data;
1153                         act->flag ^= ACT_COLLAPSED;
1154                 }
1155                         break;
1156                 case ANIMTYPE_FILLDRIVERS:
1157                 {
1158                         AnimData *adt= (AnimData* )ale->data;
1159                         adt->flag ^= ADT_DRIVERS_COLLAPSED;
1160                 }
1161                         break;
1162                 case ANIMTYPE_FILLMATD:
1163                 {
1164                         Object *ob= (Object *)ale->data;
1165                         ob->nlaflag ^= OB_ADS_SHOWMATS; // XXX 
1166                 }
1167                         break;
1168                                 
1169                 case ANIMTYPE_DSMAT:
1170                 {
1171                         Material *ma= (Material *)ale->data;
1172                         ma->flag ^= MA_DS_EXPAND;
1173                 }
1174                         break;
1175                 case ANIMTYPE_DSLAM:
1176                 {
1177                         Lamp *la= (Lamp *)ale->data;
1178                         la->flag ^= LA_DS_EXPAND;
1179                 }
1180                         break;
1181                 case ANIMTYPE_DSCAM:
1182                 {
1183                         Camera *ca= (Camera *)ale->data;
1184                         ca->flag ^= CAM_DS_EXPAND;
1185                 }
1186                         break;
1187                 case ANIMTYPE_DSCUR:
1188                 {
1189                         Curve *cu= (Curve *)ale->data;
1190                         cu->flag ^= CU_DS_EXPAND;
1191                 }
1192                         break;
1193                 case ANIMTYPE_DSSKEY:
1194                 {
1195                         Key *key= (Key *)ale->data;
1196                         key->flag ^= KEYBLOCK_DS_EXPAND;
1197                 }
1198                         break;
1199                 case ANIMTYPE_DSWOR:
1200                 {
1201                         World *wo= (World *)ale->data;
1202                         wo->flag ^= WO_DS_EXPAND;
1203                 }
1204                         break;
1205                         
1206                 case ANIMTYPE_GROUP: 
1207                 {
1208                         bActionGroup *agrp= (bActionGroup *)ale->data;
1209                         short offset= (ELEM3(ac->datatype, ANIMCONT_DOPESHEET, ANIMCONT_FCURVES, ANIMCONT_DRIVERS))? 18 : 0;
1210                         
1211                         if ((x < (offset+17)) && (agrp->channels.first)) {
1212                                 /* toggle expand */
1213                                 agrp->flag ^= AGRP_EXPANDED;
1214                         }
1215                         else if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
1216                                 /* toggle protection/locking */
1217                                 agrp->flag ^= AGRP_PROTECTED;
1218                         }
1219                         else {
1220                                 /* select/deselect group */
1221                                 if (selectmode == SELECT_INVERT) {
1222                                         /* inverse selection status of this group only */
1223                                         agrp->flag ^= AGRP_SELECTED;
1224                                 }
1225                                 else if (selectmode == -1) {
1226                                         /* select all in group (and deselect everthing else) */ 
1227                                         FCurve *fcu;
1228                                         
1229                                         /* deselect all other channels */
1230                                         ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1231                                         
1232                                         /* only select channels in group and group itself */
1233                                         for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next)
1234                                                 fcu->flag |= FCURVE_SELECTED;
1235                                         agrp->flag |= AGRP_SELECTED;                                    
1236                                 }
1237                                 else {
1238                                         /* select group by itself */
1239                                         ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1240                                         agrp->flag |= AGRP_SELECTED;
1241                                 }
1242                                 
1243                                 /* if group is selected now, make group the 'active' one in the visible list */
1244                                 if (agrp->flag & AGRP_SELECTED)
1245                                         ANIM_set_active_channel(ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
1246                         }
1247                 }
1248                         break;
1249                 case ANIMTYPE_FCURVE: 
1250                 {
1251                         FCurve *fcu= (FCurve *)ale->data;
1252                         short offset= (ac->datatype != ANIMCONT_ACTION)? 18 : 0;
1253                         
1254                         if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
1255                                 /* toggle protection */
1256                                 fcu->flag ^= FCURVE_PROTECTED;
1257                         }
1258                         else if (x >= (ACHANNEL_NAMEWIDTH-2*ACHANNEL_BUTTON_WIDTH)) {
1259                                 /* toggle mute */
1260                                 fcu->flag ^= FCURVE_MUTED;
1261                         }
1262                         else if ((x < (offset+17)) && (ac->spacetype==SPACE_IPO)) {
1263                                 /* toggle visibility */
1264                                 fcu->flag ^= FCURVE_VISIBLE;
1265                         }
1266                         else {
1267                                 /* select/deselect */
1268                                 if (selectmode == SELECT_INVERT) {
1269                                         /* inverse selection status of this F-Curve only */
1270                                         fcu->flag ^= FCURVE_SELECTED;
1271                                 }
1272                                 else {
1273                                         /* select F-Curve by itself */
1274                                         ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1275                                         fcu->flag |= FCURVE_SELECTED;
1276                                 }
1277                                 
1278                                 /* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */
1279                                 if (fcu->flag & FCURVE_SELECTED)
1280                                         ANIM_set_active_channel(ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
1281                         }
1282                 }
1283                         break;
1284                 case ANIMTYPE_GPDATABLOCK:
1285                 {
1286                         bGPdata *gpd= (bGPdata *)ale->data;
1287                         
1288                         /* toggle expand */
1289                         gpd->flag ^= GP_DATA_EXPAND;
1290                 }
1291                         break;
1292                 case ANIMTYPE_GPLAYER:
1293                 {
1294 #if 0 // XXX future of this is unclear
1295                         bGPdata *gpd= (bGPdata *)ale->owner;
1296                         bGPDlayer *gpl= (bGPDlayer *)ale->data;
1297                         
1298                         if (x >= (ACHANNEL_NAMEWIDTH-16)) {
1299                                 /* toggle lock */
1300                                 gpl->flag ^= GP_LAYER_LOCKED;
1301                         }
1302                         else if (x >= (ACHANNEL_NAMEWIDTH-32)) {
1303                                 /* toggle hide */
1304                                 gpl->flag ^= GP_LAYER_HIDE;
1305                         }
1306                         else {
1307                                 /* select/deselect */
1308                                 //if (G.qual & LR_SHIFTKEY) {
1309                                         //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
1310                                 //}
1311                                 //else {
1312                                         //deselect_gpencil_layers(data, 0);
1313                                         //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
1314                                 //}
1315                         }
1316 #endif // XXX future of this is unclear
1317                 }
1318                         break;
1319                 case ANIMTYPE_SHAPEKEY:
1320                         /* TODO: shapekey channels cannot be selected atm... */
1321                         break;
1322                 default:
1323                         printf("Error: Invalid channel type in mouse_anim_channels() \n");
1324         }
1325         
1326         /* free channels */
1327         BLI_freelistN(&anim_data);
1328 }
1329
1330 /* ------------------- */
1331
1332 /* handle clicking */
1333 static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event)
1334 {
1335         bAnimContext ac;
1336         Scene *scene;
1337         ARegion *ar;
1338         View2D *v2d;
1339         int mval[2], channel_index;
1340         short selectmode;
1341         float x, y;
1342         
1343         
1344         /* get editor data */
1345         if (ANIM_animdata_get_context(C, &ac) == 0)
1346                 return OPERATOR_CANCELLED;
1347                 
1348         /* get useful pointers from animation context data */
1349         scene= ac.scene;
1350         ar= ac.ar;
1351         v2d= &ar->v2d;
1352         
1353         /* get mouse coordinates (in region coordinates) */
1354         mval[0]= (event->x - ar->winrct.xmin);
1355         mval[1]= (event->y - ar->winrct.ymin);
1356         
1357         /* select mode is either replace (deselect all, then add) or add/extend */
1358         if (RNA_boolean_get(op->ptr, "extend_select"))
1359                 selectmode= SELECT_INVERT;
1360         else if (RNA_boolean_get(op->ptr, "select_children_only"))
1361                 selectmode= -1; /* this is a bit of a special case for ActionGroups only... should it be removed or extended to all instead? */
1362         else
1363                 selectmode= SELECT_REPLACE;
1364         
1365         /* figure out which channel user clicked in 
1366          * Note: although channels technically start at y= ACHANNEL_FIRST, we need to adjust by half a channel's height
1367          *              so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
1368          *              ACHANNEL_HEIGHT_HALF.
1369          */
1370         UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
1371         UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
1372         
1373         /* handle mouse-click in the relevant channel then */
1374         mouse_anim_channels(&ac, x, channel_index, selectmode);
1375         
1376         /* set notifier tha things have changed */
1377         ANIM_animdata_send_notifiers(C, &ac, ANIM_CHANGED_CHANNELS);
1378         
1379         return OPERATOR_FINISHED;
1380 }
1381  
1382 void ANIM_OT_channels_mouseclick (wmOperatorType *ot)
1383 {
1384         /* identifiers */
1385         ot->name= "Mouse Click on Channels";
1386         ot->idname= "ANIM_OT_channels_mouseclick";
1387         
1388         /* api callbacks */
1389         ot->invoke= animchannels_mouseclick_invoke;
1390         ot->poll= ED_operator_areaactive;
1391         
1392         /* flags */
1393         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1394         
1395         /* id-props */
1396         RNA_def_boolean(ot->srna, "extend_select", 0, "Extend Select", ""); // SHIFTKEY
1397         RNA_def_boolean(ot->srna, "select_children_only", 0, "Select Children Only", ""); // CTRLKEY|SHIFTKEY
1398 }
1399
1400 /* ************************************************************************** */
1401 /* Operator Registration */
1402
1403 void ED_operatortypes_animchannels(void)
1404 {
1405         WM_operatortype_append(ANIM_OT_channels_deselectall);
1406         WM_operatortype_append(ANIM_OT_channels_borderselect);
1407         WM_operatortype_append(ANIM_OT_channels_mouseclick);
1408         
1409         WM_operatortype_append(ANIM_OT_channels_enable_setting);
1410         WM_operatortype_append(ANIM_OT_channels_disable_setting);
1411         WM_operatortype_append(ANIM_OT_channels_toggle_setting);
1412         
1413                 // XXX does this need to be a separate operator?
1414         WM_operatortype_append(ANIM_OT_channels_toggle_editable);
1415         
1416                 // XXX these need to be updated for new system... todo...
1417         //WM_operatortype_append(ANIM_OT_channels_move_up);
1418         //WM_operatortype_append(ANIM_OT_channels_move_down);
1419         //WM_operatortype_append(ANIM_OT_channels_move_top);
1420         //WM_operatortype_append(ANIM_OT_channels_move_bottom);
1421         
1422         WM_operatortype_append(ANIM_OT_channels_visibility_toggle);
1423 }
1424
1425 void ED_keymap_animchannels(wmWindowManager *wm)
1426 {
1427         ListBase *keymap = WM_keymap_listbase(wm, "Animation_Channels", 0, 0);
1428         
1429         /* selection */
1430                 /* click-select */
1431                 // XXX for now, only leftmouse.... 
1432         WM_keymap_add_item(keymap, "ANIM_OT_channels_mouseclick", LEFTMOUSE, KM_PRESS, 0, 0);
1433         RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_mouseclick", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend_select", 1);
1434         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);
1435         
1436                 /* deselect all */
1437         WM_keymap_add_item(keymap, "ANIM_OT_channels_deselectall", AKEY, KM_PRESS, 0, 0);
1438         RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_deselectall", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
1439         
1440                 /* borderselect */
1441         WM_keymap_add_item(keymap, "ANIM_OT_channels_borderselect", BKEY, KM_PRESS, 0, 0);
1442         
1443         /* settings */
1444         WM_keymap_add_item(keymap, "ANIM_OT_channels_toggle_setting", WKEY, KM_PRESS, KM_SHIFT, 0);
1445         WM_keymap_add_item(keymap, "ANIM_OT_channels_enable_setting", WKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
1446         WM_keymap_add_item(keymap, "ANIM_OT_channels_disable_setting", WKEY, KM_PRESS, KM_ALT, 0);
1447         
1448         /* settings - specialised hotkeys */
1449         WM_keymap_add_item(keymap, "ANIM_OT_channels_toggle_editable", TABKEY, KM_PRESS, 0, 0);
1450         
1451         /* rearranging - actions only */
1452         //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_up", PAGEUPKEY, KM_PRESS, KM_SHIFT, 0);
1453         //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_down", PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0);
1454         //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_to_top", PAGEUPKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
1455         //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_to_bottom", PAGEDOWNKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
1456         
1457         /* Graph Editor only */
1458         WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_toggle", VKEY, KM_PRESS, 0, 0);
1459 }
1460
1461 /* ************************************************************************** */