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