Added support for line styles in the Graph Editor, DopeSheet
[blender-staging.git] / source / blender / editors / animation / anim_channels_edit.c
1 /**
2  * $Id$
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
21  * All rights reserved.
22  *
23  * Contributor(s): Joshua Leung
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include "MEM_guardedalloc.h"
29
30 #include "BLI_blenlib.h"
31
32 #include "DNA_anim_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_scene_types.h"
35 #include "DNA_key_types.h"
36 #include "DNA_gpencil_types.h"
37
38 #include "RNA_access.h"
39 #include "RNA_define.h"
40
41 #include "BKE_action.h"
42 #include "BKE_fcurve.h"
43 #include "BKE_context.h"
44 #include "BKE_global.h"
45
46 #include "UI_view2d.h"
47
48 #include "ED_anim_api.h"
49 #include "ED_keyframes_edit.h" // XXX move the select modes out of there!
50 #include "ED_screen.h"
51
52 #include "WM_api.h"
53 #include "WM_types.h"
54
55 /* ************************************************************************** */
56 /* CHANNELS API - Exposed API */
57
58 /* -------------------------- Selection ------------------------------------- */
59
60 /* Set the given animation-channel as the active one for the active context */
61 // TODO: extend for animdata types...
62 void ANIM_set_active_channel (bAnimContext *ac, void *data, short datatype, int filter, void *channel_data, short channel_type)
63 {
64         ListBase anim_data = {NULL, NULL};
65         bAnimListElem *ale;
66         
67         /* try to build list of filtered items */
68         ANIM_animdata_filter(ac, &anim_data, filter, data, datatype);
69         if (anim_data.first == NULL)
70                 return;
71                 
72         /* only clear the 'active' flag for the channels of the same type */
73         for (ale= anim_data.first; ale; ale= ale->next) {
74                 /* skip if types don't match */
75                 if (channel_type != ale->type)
76                         continue;
77                 
78                 /* flag to set depends on type */
79                 switch (ale->type) {
80                         case ANIMTYPE_GROUP:
81                         {
82                                 bActionGroup *agrp= (bActionGroup *)ale->data;
83                                 
84                                 ACHANNEL_SET_FLAG(agrp, ACHANNEL_SETFLAG_CLEAR, AGRP_ACTIVE);
85                         }
86                                 break;
87                         case ANIMTYPE_FCURVE:
88                         {
89                                 FCurve *fcu= (FCurve *)ale->data;
90                                 
91                                 ACHANNEL_SET_FLAG(fcu, ACHANNEL_SETFLAG_CLEAR, FCURVE_ACTIVE);
92                         }
93                                 break;
94                         case ANIMTYPE_NLATRACK:
95                         {
96                                 NlaTrack *nlt= (NlaTrack *)ale->data;
97                                 
98                                 ACHANNEL_SET_FLAG(nlt, ACHANNEL_SETFLAG_CLEAR, NLATRACK_ACTIVE);
99                         }
100                                 break;
101                         
102                         case ANIMTYPE_FILLACTD: /* Action Expander */
103                         case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
104                         case ANIMTYPE_DSLAM:
105                         case ANIMTYPE_DSCAM:
106                         case ANIMTYPE_DSCUR:
107                         case ANIMTYPE_DSSKEY:
108                         case ANIMTYPE_DSWOR:
109                         case ANIMTYPE_DSPART:
110                         case ANIMTYPE_DSMBALL:
111                         case ANIMTYPE_DSARM:
112                         case ANIMTYPE_DSMESH:
113                         {
114                                 /* need to verify that this data is valid for now */
115                                 if (ale->adt) {
116                                         ACHANNEL_SET_FLAG(ale->adt, ACHANNEL_SETFLAG_CLEAR, ADT_UI_ACTIVE);
117                                 }
118                         }
119                                 break;
120                 }
121         }
122         
123         /* set active flag */
124         if (channel_data) {
125                 switch (channel_type) {
126                         case ANIMTYPE_GROUP:
127                         {
128                                 bActionGroup *agrp= (bActionGroup *)channel_data;
129                                 agrp->flag |= AGRP_ACTIVE;
130                         }
131                                 break;
132                         case ANIMTYPE_FCURVE:
133                         {
134                                 FCurve *fcu= (FCurve *)channel_data;
135                                 fcu->flag |= FCURVE_ACTIVE;
136                         }
137                                 break;
138                         case ANIMTYPE_NLATRACK:
139                         {
140                                 NlaTrack *nlt= (NlaTrack *)channel_data;
141                                 nlt->flag |= NLATRACK_ACTIVE;
142                         }
143                                 break;
144                                 
145                         case ANIMTYPE_FILLACTD: /* Action Expander */
146                         case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
147                         case ANIMTYPE_DSLAM:
148                         case ANIMTYPE_DSCAM:
149                         case ANIMTYPE_DSCUR:
150                         case ANIMTYPE_DSSKEY:
151                         case ANIMTYPE_DSWOR:
152                         case ANIMTYPE_DSPART:
153                         case ANIMTYPE_DSMBALL:
154                         case ANIMTYPE_DSARM:
155                         case ANIMTYPE_DSMESH:
156                         {
157                                 /* need to verify that this data is valid for now */
158                                 if (ale->adt)
159                                         ale->adt->flag |= ADT_UI_ACTIVE;
160                         }
161                                 break;
162                 }
163         }
164         
165         /* clean up */
166         BLI_freelistN(&anim_data);
167 }
168
169 /* Deselect all animation channels 
170  *      - data: pointer to datatype, as contained in bAnimContext
171  *      - datatype: the type of data that 'data' represents (eAnimCont_Types)
172  *      - test: check if deselecting instead of selecting
173  *      - sel: eAnimChannels_SetFlag;
174  */
175 void ANIM_deselect_anim_channels (bAnimContext *ac, void *data, short datatype, short test, short sel)
176 {
177         ListBase anim_data = {NULL, NULL};
178         bAnimListElem *ale;
179         int filter;
180         
181         /* filter data */
182         filter= ANIMFILTER_VISIBLE|ANIMFILTER_CHANNELS;
183         ANIM_animdata_filter(ac, &anim_data, filter, data, datatype);
184         
185         /* See if we should be selecting or deselecting */
186         if (test) {
187                 for (ale= anim_data.first; ale; ale= ale->next) {
188                         if (sel == 0) 
189                                 break;
190                         
191                         switch (ale->type) {
192                                 case ANIMTYPE_SCENE:
193                                         if (ale->flag & SCE_DS_SELECTED)
194                                                 sel= ACHANNEL_SETFLAG_CLEAR;
195                                         break;
196                                 case ANIMTYPE_OBJECT:
197                                 #if 0   /* for now, do not take object selection into account, since it gets too annoying */
198                                         if (ale->flag & SELECT)
199                                                 sel= ACHANNEL_SETFLAG_CLEAR;
200                                 #endif
201                                         break;
202                                 case ANIMTYPE_GROUP:
203                                         if (ale->flag & AGRP_SELECTED)
204                                                 sel= ACHANNEL_SETFLAG_CLEAR;
205                                         break;
206                                 case ANIMTYPE_FCURVE:
207                                         if (ale->flag & FCURVE_SELECTED)
208                                                 sel= ACHANNEL_SETFLAG_CLEAR;
209                                         break;
210                                 case ANIMTYPE_SHAPEKEY:
211                                         if (ale->flag & KEYBLOCK_SEL)
212                                                 sel= ACHANNEL_SETFLAG_CLEAR;
213                                         break;
214                                 case ANIMTYPE_NLATRACK:
215                                         if (ale->flag & NLATRACK_SELECTED)
216                                                 sel= ACHANNEL_SETFLAG_CLEAR;
217                                         break;
218                                         
219                                 case ANIMTYPE_FILLACTD: /* Action Expander */
220                                 case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
221                                 case ANIMTYPE_DSLAM:
222                                 case ANIMTYPE_DSCAM:
223                                 case ANIMTYPE_DSCUR:
224                                 case ANIMTYPE_DSSKEY:
225                                 case ANIMTYPE_DSWOR:
226                                 case ANIMTYPE_DSPART:
227                                 case ANIMTYPE_DSMBALL:
228                                 case ANIMTYPE_DSARM:
229                                 case ANIMTYPE_DSMESH:
230                                 case ANIMTYPE_DSNTREE:
231                                 case ANIMTYPE_DSTEX:
232                                 case ANIMTYPE_DSLINESTYLE:
233                                 {
234                                         if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
235                                                 sel= ACHANNEL_SETFLAG_CLEAR;
236                                 }
237                                         break;
238                         }
239                 }
240         }
241                 
242         /* Now set the flags */
243         for (ale= anim_data.first; ale; ale= ale->next) {
244                 switch (ale->type) {
245                         case ANIMTYPE_SCENE:
246                         {
247                                 Scene *scene= (Scene *)ale->data;
248                                 
249                                 ACHANNEL_SET_FLAG(scene, sel, SCE_DS_SELECTED);
250                                 
251                                 if (scene->adt) {
252                                         ACHANNEL_SET_FLAG(scene, sel, ADT_UI_SELECTED);
253                                 }
254                         }
255                                 break;
256                         case ANIMTYPE_OBJECT:
257                         #if 0   /* for now, do not take object selection into account, since it gets too annoying */
258                         {
259                                 Base *base= (Base *)ale->data;
260                                 Object *ob= base->object;
261                                 
262                                 ACHANNEL_SET_FLAG(base, sel, SELECT);
263                                 ACHANNEL_SET_FLAG(ob, sel, SELECT);
264                                 
265                                 if (ob->adt) {
266                                         ACHANNEL_SET_FLAG(ob, sel, ADT_UI_SELECTED);
267                                 }
268                         }
269                         #endif
270                                 break;
271                         case ANIMTYPE_GROUP:
272                         {
273                                 bActionGroup *agrp= (bActionGroup *)ale->data;
274                                 
275                                 ACHANNEL_SET_FLAG(agrp, sel, AGRP_SELECTED);
276                                 agrp->flag &= ~AGRP_ACTIVE;
277                         }
278                                 break;
279                         case ANIMTYPE_FCURVE:
280                         {
281                                 FCurve *fcu= (FCurve *)ale->data;
282                                 
283                                 ACHANNEL_SET_FLAG(fcu, sel, FCURVE_SELECTED);
284                                 fcu->flag &= ~FCURVE_ACTIVE;
285                         }
286                                 break;
287                         case ANIMTYPE_SHAPEKEY:
288                         {
289                                 KeyBlock *kb= (KeyBlock *)ale->data;
290                                 
291                                 ACHANNEL_SET_FLAG(kb, sel, KEYBLOCK_SEL);
292                         }
293                                 break;
294                         case ANIMTYPE_NLATRACK:
295                         {
296                                 NlaTrack *nlt= (NlaTrack *)ale->data;
297                                 
298                                 ACHANNEL_SET_FLAG(nlt, sel, NLATRACK_SELECTED);
299                                 nlt->flag &= ~NLATRACK_ACTIVE;
300                         }
301                                 break;
302                                 
303                         case ANIMTYPE_FILLACTD: /* Action Expander */
304                         case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
305                         case ANIMTYPE_DSLAM:
306                         case ANIMTYPE_DSCAM:
307                         case ANIMTYPE_DSCUR:
308                         case ANIMTYPE_DSSKEY:
309                         case ANIMTYPE_DSWOR:
310                         case ANIMTYPE_DSPART:
311                         case ANIMTYPE_DSMBALL:
312                         case ANIMTYPE_DSARM:
313                         case ANIMTYPE_DSMESH:
314                         case ANIMTYPE_DSNTREE:
315                         case ANIMTYPE_DSTEX:
316                         case ANIMTYPE_DSLINESTYLE:
317                         {
318                                 /* need to verify that this data is valid for now */
319                                 if (ale->adt) {
320                                         ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED);
321                                         ale->adt->flag &= ~ADT_UI_ACTIVE;
322                                 }
323                         }
324                                 break;
325                 }
326         }
327         
328         /* Cleanup */
329         BLI_freelistN(&anim_data);
330 }
331
332 /* ---------------------------- Graph Editor ------------------------------------- */
333
334 /* Flush visibility (for Graph Editor) changes up/down hierarchy for changes in the given setting 
335  *      - anim_data: list of the all the anim channels that can be chosen
336  *              -> filtered using ANIMFILTER_CHANNELS only, since if we took VISIBLE too,
337  *                then the channels under closed expanders get ignored...
338  *      - ale_setting: the anim channel (not in the anim_data list directly, though occuring there)
339  *              with the new state of the setting that we want flushed up/down the hierarchy 
340  *      - setting: type of setting to set
341  *      - on: whether the visibility setting has been enabled or disabled 
342  */
343 void ANIM_flush_setting_anim_channels (bAnimContext *ac, ListBase *anim_data, bAnimListElem *ale_setting, int setting, short on)
344 {
345         bAnimListElem *ale, *match=NULL;
346         int prevLevel=0, matchLevel=0;
347         
348         /* sanity check */
349         if (ELEM(NULL, anim_data, anim_data->first))
350                 return;
351         
352         /* find the channel that got changed */
353         for (ale= anim_data->first; ale; ale= ale->next) {
354                 /* compare data, and type as main way of identifying the channel */
355                 if ((ale->data == ale_setting->data) && (ale->type == ale_setting->type)) {
356                         /* we also have to check the ID, this is assigned to, since a block may have multiple users */
357                         // TODO: is the owner-data more revealing?
358                         if (ale->id == ale_setting->id) {
359                                 match= ale;
360                                 break;
361                         }
362                 }
363         }
364         if (match == NULL) {
365                 printf("ERROR: no channel matching the one changed was found \n");
366                 return;
367         }
368         else {
369                 bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale_setting);
370                 
371                 if (acf == NULL) {
372                         printf("ERROR: no channel info for the changed channel \n");
373                         return;
374                 }
375                 
376                 /* get the level of the channel that was affected
377                  *       - we define the level as simply being the offset for the start of the channel
378                  */
379                 matchLevel= (acf->get_offset)? acf->get_offset(ac, ale_setting) : 0;
380                 prevLevel= matchLevel;
381         }
382         
383         /* flush up? 
384          *
385          * For Visibility:
386          *      - only flush up if the current state is now enabled (positive 'on' state is default) 
387          *        (otherwise, it's too much work to force the parents to be inactive too)
388          *
389          * For everything else:
390          *      - only flush up if the current state is now disabled (negative 'off' state is default)
391          *        (otherwise, it's too much work to force the parents to be active too)
392          */
393         if ( ((setting == ACHANNEL_SETTING_VISIBLE) && on) ||
394                  ((setting != ACHANNEL_SETTING_VISIBLE) && on==0) )
395         {
396                 /* go backwards in the list, until the highest-ranking element (by indention has been covered) */
397                 for (ale= match->prev; ale; ale= ale->prev) {
398                         bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale);
399                         int level;
400                         
401                         /* if no channel info was found, skip, since this type might not have any useful info */
402                         if (acf == NULL)
403                                 continue;
404                         
405                         /* get the level of the current channel traversed 
406                          *       - we define the level as simply being the offset for the start of the channel
407                          */
408                         level= (acf->get_offset)? acf->get_offset(ac, ale) : 0;
409                         
410                         /* if the level is 'less than' (i.e. more important) the level we're matching
411                          * but also 'less than' the level just tried (i.e. only the 1st group above grouped F-Curves, 
412                          * when toggling visibility of F-Curves, gets flushed, which should happen if we don't let prevLevel
413                          * get updated below once the first 1st group is found)...
414                          */
415                         if (level < prevLevel) {
416                                 /* flush the new status... */
417                                 ANIM_channel_setting_set(ac, ale, setting, on);
418                                 
419                                 /* store this level as the 'old' level now */
420                                 prevLevel= level;
421                         }       
422                         /* if the level is 'greater than' (i.e. less important) than the previous level... */
423                         else if (level > prevLevel) {
424                                 /* if previous level was a base-level (i.e. 0 offset / root of one hierarchy),
425                                  * stop here
426                                  */
427                                 if (prevLevel == 0)
428                                         break;
429                                 /* otherwise, this level weaves into another sibling hierarchy to the previous one just
430                                  * finished, so skip until we get to the parent of this level 
431                                  */
432                                 else
433                                         continue;
434                         }
435                 }
436         }
437         
438         /* flush down (always) */
439         {
440                 /* go forwards in the list, until the lowest-ranking element (by indention has been covered) */
441                 for (ale= match->next; ale; ale= ale->next) {
442                         bAnimChannelType *acf= ANIM_channel_get_typeinfo(ale);
443                         int level;
444                         
445                         /* if no channel info was found, skip, since this type might not have any useful info */
446                         if (acf == NULL)
447                                 continue;
448                         
449                         /* get the level of the current channel traversed 
450                          *       - we define the level as simply being the offset for the start of the channel
451                          */
452                         level= (acf->get_offset)? acf->get_offset(ac, ale) : 0;
453                         
454                         /* if the level is 'greater than' (i.e. less important) the channel that was changed, 
455                          * flush the new status...
456                          */
457                         if (level > matchLevel)
458                                 ANIM_channel_setting_set(ac, ale, setting, on);
459                         /* however, if the level is 'less than or equal to' the channel that was changed,
460                          * (i.e. the current channel is as important if not more important than the changed channel)
461                          * then we should stop, since we've found the last one of the children we should flush
462                          */
463                         else
464                                 break;
465                         
466                         /* store this level as the 'old' level now */
467                         prevLevel= level;
468                 }
469         }
470 }
471
472 /* -------------------------- F-Curves ------------------------------------- */
473
474 /* Delete the given F-Curve from its AnimData block */
475 void ANIM_fcurve_delete_from_animdata (bAnimContext *ac, AnimData *adt, FCurve *fcu)
476 {
477         /* - if no AnimData, we've got nowhere to remove the F-Curve from 
478          *      (this doesn't guarantee that the F-Curve is in there, but at least we tried
479          * - if no F-Curve, there is nothing to remove
480          */
481         if (ELEM(NULL, adt, fcu))
482                 return;
483                 
484         /* remove from whatever list it came from
485          *      - Action Group
486          *      - Action
487          *      - Drivers
488          *      - TODO... some others?
489          */
490         if (fcu->grp)
491                 action_groups_remove_channel(adt->action, fcu);
492         else if ((ac) && (ac->datatype == ANIMCONT_DRIVERS))
493                 BLI_remlink(&adt->drivers, fcu);
494         else if (adt->action)
495                 BLI_remlink(&adt->action->curves, fcu);
496                 
497         /* free the F-Curve itself */
498         free_fcurve(fcu);
499 }
500
501 /* ************************************************************************** */
502 /* OPERATORS */
503
504 /* ****************** Operator Utilities ********************************** */
505
506 /* poll callback for being in an Animation Editor channels list region */
507 int animedit_poll_channels_active (bContext *C)
508 {
509         ScrArea *sa= CTX_wm_area(C);
510         
511         /* channels region test */
512         // TODO: could enhance with actually testing if channels region?
513         if (ELEM(NULL, sa, CTX_wm_region(C)))
514                 return 0;
515         /* animation editor test */
516         if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
517                 return 0;
518                 
519         return 1;
520 }
521
522 /* poll callback for Animation Editor channels list region + not in NLA-tweakmode for NLA */
523 int animedit_poll_channels_nla_tweakmode_off (bContext *C)
524 {
525         ScrArea *sa= CTX_wm_area(C);
526         Scene *scene = CTX_data_scene(C);
527         
528         /* channels region test */
529         // TODO: could enhance with actually testing if channels region?
530         if (ELEM(NULL, sa, CTX_wm_region(C)))
531                 return 0;
532         /* animation editor test */
533         if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
534                 return 0;
535         
536         /* NLA TweakMode test */        
537         if (sa->spacetype == SPACE_NLA) {
538                 if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON))
539                         return 0;
540         }
541                 
542         return 1;
543 }
544
545 /* ****************** Rearrange Channels Operator ******************* */
546 /* This operator only works for Action Editor mode for now, as having it elsewhere makes things difficult */
547
548 #if 0 // XXX old animation system - needs to be updated for new system...
549
550 /* constants for channel rearranging */
551 /* WARNING: don't change exising ones without modifying rearrange func accordingly */
552 enum {
553         REARRANGE_ACTCHAN_TOP= -2,
554         REARRANGE_ACTCHAN_UP= -1,
555         REARRANGE_ACTCHAN_DOWN= 1,
556         REARRANGE_ACTCHAN_BOTTOM= 2
557 };
558
559 /* make sure all action-channels belong to a group (and clear action's list) */
560 static void split_groups_action_temp (bAction *act, bActionGroup *tgrp)
561 {
562         bActionChannel *achan;
563         bActionGroup *agrp;
564         
565         /* Separate action-channels into lists per group */
566         for (agrp= act->groups.first; agrp; agrp= agrp->next) {
567                 if (agrp->channels.first) {
568                         achan= agrp->channels.last;
569                         act->chanbase.first= achan->next;
570                         
571                         achan= agrp->channels.first;
572                         achan->prev= NULL;
573                         
574                         achan= agrp->channels.last;
575                         achan->next= NULL;
576                 }
577         }
578         
579         /* Initialise memory for temp-group */
580         memset(tgrp, 0, sizeof(bActionGroup));
581         tgrp->flag |= (AGRP_EXPANDED|AGRP_TEMP);
582         strcpy(tgrp->name, "#TempGroup");
583                 
584         /* Move any action-channels not already moved, to the temp group */
585         if (act->chanbase.first) {
586                 /* start of list */
587                 achan= act->chanbase.first;
588                 achan->prev= NULL;
589                 tgrp->channels.first= achan;
590                 act->chanbase.first= NULL;
591                 
592                 /* end of list */
593                 achan= act->chanbase.last;
594                 achan->next= NULL;
595                 tgrp->channels.last= achan;
596                 act->chanbase.last= NULL;
597         }
598         
599         /* Add temp-group to list */
600         BLI_addtail(&act->groups, tgrp);
601 }
602
603 /* link lists of channels that groups have */
604 static void join_groups_action_temp (bAction *act)
605 {
606         bActionGroup *agrp;
607         bActionChannel *achan;
608         
609         for (agrp= act->groups.first; agrp; agrp= agrp->next) {
610                 ListBase tempGroup;
611                 
612                 /* add list of channels to action's channels */
613                 tempGroup= agrp->channels;
614                 addlisttolist(&act->chanbase, &agrp->channels);
615                 agrp->channels= tempGroup;
616                 
617                 /* clear moved flag */
618                 agrp->flag &= ~AGRP_MOVED;
619                 
620                 /* if temp-group... remove from list (but don't free as it's on the stack!) */
621                 if (agrp->flag & AGRP_TEMP) {
622                         BLI_remlink(&act->groups, agrp);
623                         break;
624                 }
625         }
626         
627         /* clear "moved" flag from all achans */
628         for (achan= act->chanbase.first; achan; achan= achan->next) 
629                 achan->flag &= ~ACHAN_MOVED;
630 }
631
632
633 static short rearrange_actchannel_is_ok (Link *channel, short type)
634 {
635         if (type == ANIMTYPE_GROUP) {
636                 bActionGroup *agrp= (bActionGroup *)channel;
637                 
638                 if (SEL_AGRP(agrp) && !(agrp->flag & AGRP_MOVED))
639                         return 1;
640         }
641         else if (type == ANIMTYPE_ACHAN) {
642                 bActionChannel *achan= (bActionChannel *)channel;
643                 
644                 if (VISIBLE_ACHAN(achan) && SEL_ACHAN(achan) && !(achan->flag & ACHAN_MOVED))
645                         return 1;
646         }
647         
648         return 0;
649 }
650
651 static short rearrange_actchannel_after_ok (Link *channel, short type)
652 {
653         if (type == ANIMTYPE_GROUP) {
654                 bActionGroup *agrp= (bActionGroup *)channel;
655                 
656                 if (agrp->flag & AGRP_TEMP)
657                         return 0;
658         }
659         
660         return 1;
661 }
662
663
664 static short rearrange_actchannel_top (ListBase *list, Link *channel, short type)
665 {
666         if (rearrange_actchannel_is_ok(channel, type)) {
667                 /* take it out off the chain keep data */
668                 BLI_remlink(list, channel);
669                 
670                 /* make it first element */
671                 BLI_insertlinkbefore(list, list->first, channel);
672                 
673                 return 1;
674         }
675         
676         return 0;
677 }
678
679 static short rearrange_actchannel_up (ListBase *list, Link *channel, short type)
680 {
681         if (rearrange_actchannel_is_ok(channel, type)) {
682                 Link *prev= channel->prev;
683                 
684                 if (prev) {
685                         /* take it out off the chain keep data */
686                         BLI_remlink(list, channel);
687                         
688                         /* push it up */
689                         BLI_insertlinkbefore(list, prev, channel);
690                         
691                         return 1;
692                 }
693         }
694         
695         return 0;
696 }
697
698 static short rearrange_actchannel_down (ListBase *list, Link *channel, short type)
699 {
700         if (rearrange_actchannel_is_ok(channel, type)) {
701                 Link *next = (channel->next) ? channel->next->next : NULL;
702                 
703                 if (next) {
704                         /* take it out off the chain keep data */
705                         BLI_remlink(list, channel);
706                         
707                         /* move it down */
708                         BLI_insertlinkbefore(list, next, channel);
709                         
710                         return 1;
711                 }
712                 else if (rearrange_actchannel_after_ok(list->last, type)) {
713                         /* take it out off the chain keep data */
714                         BLI_remlink(list, channel);
715                         
716                         /* add at end */
717                         BLI_addtail(list, channel);
718                         
719                         return 1;
720                 }
721                 else {
722                         /* take it out off the chain keep data */
723                         BLI_remlink(list, channel);
724                         
725                         /* add just before end */
726                         BLI_insertlinkbefore(list, list->last, channel);
727                         
728                         return 1;
729                 }
730         }
731         
732         return 0;
733 }
734
735 static short rearrange_actchannel_bottom (ListBase *list, Link *channel, short type)
736 {
737         if (rearrange_actchannel_is_ok(channel, type)) {
738                 if (rearrange_actchannel_after_ok(list->last, type)) {
739                         /* take it out off the chain keep data */
740                         BLI_remlink(list, channel);
741                         
742                         /* add at end */
743                         BLI_addtail(list, channel);
744                         
745                         return 1;
746                 }
747         }
748         
749         return 0;
750 }
751
752
753 /* Change the order of action-channels 
754  *      mode: REARRANGE_ACTCHAN_*  
755  */
756 static void rearrange_action_channels (bAnimContext *ac, short mode)
757 {
758         bAction *act;
759         bActionChannel *achan, *chan;
760         bActionGroup *agrp, *grp;
761         bActionGroup tgrp;
762         
763         short (*rearrange_func)(ListBase *, Link *, short);
764         short do_channels = 1;
765         
766         /* Get the active action, exit if none are selected */
767         act= (bAction *)ac->data;
768         
769         /* exit if invalid mode */
770         switch (mode) {
771                 case REARRANGE_ACTCHAN_TOP:
772                         rearrange_func= rearrange_actchannel_top;
773                         break;
774                 case REARRANGE_ACTCHAN_UP:
775                         rearrange_func= rearrange_actchannel_up;
776                         break;
777                 case REARRANGE_ACTCHAN_DOWN:
778                         rearrange_func= rearrange_actchannel_down;
779                         break;
780                 case REARRANGE_ACTCHAN_BOTTOM:
781                         rearrange_func= rearrange_actchannel_bottom;
782                         break;
783                 default:
784                         return;
785         }
786         
787         /* make sure we're only operating with groups */
788         split_groups_action_temp(act, &tgrp);
789         
790         /* rearrange groups first (and then, only consider channels if the groups weren't moved) */
791         #define GET_FIRST(list) ((mode > 0) ? (list.first) : (list.last))
792         #define GET_NEXT(item) ((mode > 0) ? (item->next) : (item->prev))
793         
794         for (agrp= GET_FIRST(act->groups); agrp; agrp= grp) {
795                 /* Get next group to consider */
796                 grp= GET_NEXT(agrp);
797                 
798                 /* try to do group first */
799                 if (rearrange_func(&act->groups, (Link *)agrp, ANIMTYPE_GROUP)) {
800                         do_channels= 0;
801                         agrp->flag |= AGRP_MOVED;
802                 }
803         }
804         
805         if (do_channels) {
806                 for (agrp= GET_FIRST(act->groups); agrp; agrp= grp) {
807                         /* Get next group to consider */
808                         grp= GET_NEXT(agrp);
809                         
810                         /* only consider action-channels if they're visible (group expanded) */
811                         if (EXPANDED_AGRP(agrp)) {
812                                 for (achan= GET_FIRST(agrp->channels); achan; achan= chan) {
813                                         /* Get next channel to consider */
814                                         chan= GET_NEXT(achan);
815                                         
816                                         /* Try to do channel */
817                                         if (rearrange_func(&agrp->channels, (Link *)achan, ANIMTYPE_ACHAN))
818                                                 achan->flag |= ACHAN_MOVED;
819                                 }
820                         }
821                 }
822         }
823         #undef GET_FIRST
824         #undef GET_NEXT
825         
826         /* assemble lists into one list (and clear moved tags) */
827         join_groups_action_temp(act);
828 }
829
830 /* ------------------- */
831
832 static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
833 {
834         bAnimContext ac;
835         short mode;
836         
837         /* get editor data - only for Action Editor (for now) */
838         if (ANIM_animdata_get_context(C, &ac) == 0)
839                 return OPERATOR_CANCELLED;
840         if (ac.datatype != ANIMCONT_ACTION)
841                 return OPERATOR_PASS_THROUGH;
842                 
843         /* get mode, then rearrange channels */
844         mode= RNA_enum_get(op->ptr, "direction");
845         rearrange_action_channels(&ac, mode);
846         
847         /* send notifier that things have changed */
848         WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
849         
850         return OPERATOR_FINISHED;
851 }
852  
853
854 void ANIM_OT_channels_move_up (wmOperatorType *ot)
855 {
856         /* identifiers */
857         ot->name= "Move Channel(s) Up";
858         ot->idname= "ANIM_OT_channels_move_up";
859         
860         /* api callbacks */
861         ot->exec= animchannels_rearrange_exec;
862         ot->poll= ED_operator_areaactive;
863         
864         /* flags */
865         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
866         
867         /* props */
868         RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_UP, "Direction", "");
869 }
870
871 void ANIM_OT_channels_move_down (wmOperatorType *ot)
872 {
873         /* identifiers */
874         ot->name= "Move Channel(s) Down";
875         ot->idname= "ANIM_OT_channels_move_down";
876         
877         /* api callbacks */
878         ot->exec= animchannels_rearrange_exec;
879         ot->poll= ED_operator_areaactive;
880         
881         /* flags */
882         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
883         
884         /* props */
885         RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_DOWN, "Direction", "");
886 }
887
888 void ANIM_OT_channels_move_top (wmOperatorType *ot)
889 {
890         /* identifiers */
891         ot->name= "Move Channel(s) to Top";
892         ot->idname= "ANIM_OT_channels_move_to_top";
893         
894         /* api callbacks */
895         ot->exec= animchannels_rearrange_exec;
896         ot->poll= ED_operator_areaactive;
897         
898         /* flags */
899         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
900         
901         /* props */
902         RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_TOP, "Direction", "");
903 }
904
905 void ANIM_OT_channels_move_bottom (wmOperatorType *ot)
906 {
907         /* identifiers */
908         ot->name= "Move Channel(s) to Bottom";
909         ot->idname= "ANIM_OT_channels_move_to_bottom";
910         
911         /* api callbacks */
912         ot->exec= animchannels_rearrange_exec;
913         ot->poll= ED_operator_areaactive;
914         
915         /* flags */
916         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
917         
918         /* props */
919         RNA_def_enum(ot->srna, "direction", NULL /* XXX add enum for this */, REARRANGE_ACTCHAN_BOTTOM, "Direction", "");
920 }
921
922 #endif // XXX old animation system - needs to be updated for new system...
923
924 /* ******************** Delete Channel Operator *********************** */
925
926 static int animchannels_delete_exec(bContext *C, wmOperator *op)
927 {
928         bAnimContext ac;
929         ListBase anim_data = {NULL, NULL};
930         bAnimListElem *ale;
931         int filter;
932         
933         /* get editor data */
934         if (ANIM_animdata_get_context(C, &ac) == 0)
935                 return OPERATOR_CANCELLED;
936         
937         /* cannot delete in shapekey */
938         if (ac.datatype == ANIMCONT_SHAPEKEY) 
939                 return OPERATOR_CANCELLED;
940                 
941                 
942         /* do groups only first (unless in Drivers mode, where there are none) */
943         if (ac.datatype != ANIMCONT_DRIVERS) {
944                 /* filter data */
945                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_CHANNELS | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
946                 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
947                 
948                 /* delete selected groups and their associated channels */
949                 for (ale= anim_data.first; ale; ale= ale->next) {
950                         /* only groups - don't check other types yet, since they may no-longer exist */
951                         if (ale->type == ANIMTYPE_GROUP) {
952                                 bActionGroup *agrp= (bActionGroup *)ale->data;
953                                 AnimData *adt= ale->adt;
954                                 FCurve *fcu, *fcn;
955                                 
956                                 /* skip this group if no AnimData available, as we can't safely remove the F-Curves */
957                                 if (adt == NULL)
958                                         continue;
959                                 
960                                 /* delete all of the Group's F-Curves, but no others */
961                                 for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcn) {
962                                         fcn= fcu->next;
963                                         
964                                         /* remove from group and action, then free */
965                                         action_groups_remove_channel(adt->action, fcu);
966                                         free_fcurve(fcu);
967                                 }
968                                 
969                                 /* free the group itself */
970                                 if (adt->action)
971                                         BLI_freelinkN(&adt->action->groups, agrp);
972                                 else
973                                         MEM_freeN(agrp);
974                         }
975                 }
976                 
977                 /* cleanup */
978                 BLI_freelistN(&anim_data);
979         }
980         
981         /* now do F-Curves */
982         if (ac.datatype != ANIMCONT_GPENCIL) {
983                 /* filter data */
984                 filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
985                 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
986                 
987                 /* delete selected F-Curves */
988                 for (ale= anim_data.first; ale; ale= ale->next) {
989                         /* only F-Curves, and only if we can identify its parent */
990                         if (ale->type == ANIMTYPE_FCURVE) {
991                                 AnimData *adt= ale->adt;
992                                 FCurve *fcu= (FCurve *)ale->data;
993                                 
994                                 /* try to free F-Curve */
995                                 ANIM_fcurve_delete_from_animdata(&ac, adt, fcu);
996                         }
997                 }
998                 
999                 /* cleanup */
1000                 BLI_freelistN(&anim_data);
1001         }
1002         
1003         /* send notifier that things have changed */
1004         WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1005         
1006         return OPERATOR_FINISHED;
1007 }
1008  
1009 void ANIM_OT_channels_delete (wmOperatorType *ot)
1010 {
1011         /* identifiers */
1012         ot->name= "Delete Channels";
1013         ot->idname= "ANIM_OT_channels_delete";
1014         ot->description= "Delete all selected animation channels";
1015         
1016         /* api callbacks */
1017         ot->exec= animchannels_delete_exec;
1018         ot->poll= animedit_poll_channels_active;
1019         
1020         /* flags */
1021         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1022 }
1023
1024 /* ******************** Set Channel Visibility Operator *********************** */
1025 /* NOTE: this operator is only valid in the Graph Editor channels region */
1026
1027 static int animchannels_visibility_set_exec(bContext *C, wmOperator *op)
1028 {
1029         bAnimContext ac;
1030         ListBase anim_data = {NULL, NULL};
1031         ListBase all_data = {NULL, NULL};
1032         bAnimListElem *ale;
1033         int filter;
1034         
1035         /* get editor data */
1036         if (ANIM_animdata_get_context(C, &ac) == 0)
1037                 return OPERATOR_CANCELLED;
1038         
1039         /* get list of all channels that selection may need to be flushed to */
1040         filter= ANIMFILTER_CHANNELS;
1041         ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
1042         
1043         /* hide all channels not selected */
1044         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_UNSEL | ANIMFILTER_NODUPLIS);
1045         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1046         
1047         for (ale= anim_data.first; ale; ale= ale->next) {
1048                 /* clear setting first */
1049                 ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_CLEAR);
1050                 
1051                 /* now also flush selection status as appropriate 
1052                  * NOTE: in some cases, this may result in repeat flushing being performed
1053                  */
1054                 ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 0);
1055         }
1056         
1057         BLI_freelistN(&anim_data);
1058         
1059         /* make all the selected channels visible */
1060         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
1061         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1062         
1063         for (ale= anim_data.first; ale; ale= ale->next) {
1064                 /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */
1065                 // TODO: find out why this is the case, and fix that
1066                 if (ale->type == ANIMTYPE_OBJECT)
1067                         continue;
1068                 
1069                 /* enable the setting */
1070                 ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_ADD);
1071                 
1072                 /* now, also flush selection status up/down as appropriate */
1073                 ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 1);
1074         }
1075         
1076         BLI_freelistN(&anim_data);
1077         BLI_freelistN(&all_data);
1078         
1079         
1080         /* send notifier that things have changed */
1081         WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1082         
1083         return OPERATOR_FINISHED;
1084 }
1085
1086 void ANIM_OT_channels_visibility_set (wmOperatorType *ot)
1087 {
1088         /* identifiers */
1089         ot->name= "Set Visibility";
1090         ot->idname= "ANIM_OT_channels_visibility_set";
1091         ot->description= "Make only the selected animation channels visible in the Graph Editor";
1092         
1093         /* api callbacks */
1094         ot->exec= animchannels_visibility_set_exec;
1095         ot->poll= ED_operator_ipo_active;
1096         
1097         /* flags */
1098         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1099 }
1100
1101
1102 /* ******************** Toggle Channel Visibility Operator *********************** */
1103 /* NOTE: this operator is only valid in the Graph Editor channels region */
1104
1105 static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *op)
1106 {
1107         bAnimContext ac;
1108         ListBase anim_data = {NULL, NULL};
1109         ListBase all_data = {NULL, NULL};
1110         bAnimListElem *ale;
1111         int filter;
1112         short vis= ACHANNEL_SETFLAG_ADD;
1113         
1114         /* get editor data */
1115         if (ANIM_animdata_get_context(C, &ac) == 0)
1116                 return OPERATOR_CANCELLED;
1117                 
1118         /* get list of all channels that selection may need to be flushed to */
1119         filter= (ANIMFILTER_CHANNELS | ANIMFILTER_NODUPLIS);
1120         ANIM_animdata_filter(&ac, &all_data, filter, ac.data, ac.datatype);
1121                 
1122         /* filter data */
1123         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
1124         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1125         
1126         /* See if we should be making showing all selected or hiding */
1127         for (ale= anim_data.first; ale; ale= ale->next) {
1128                 /* set the setting in the appropriate way (if available) */
1129                 if (ANIM_channel_setting_get(&ac, ale, ACHANNEL_SETTING_VISIBLE)) {
1130                         vis= ACHANNEL_SETFLAG_CLEAR;
1131                         break;
1132                 }
1133         }
1134
1135         /* Now set the flags */
1136         for (ale= anim_data.first; ale; ale= ale->next) {
1137                 /* hack: skip object channels for now, since flushing those will always flush everything, but they are always included */
1138                 // TODO: find out why this is the case, and fix that
1139                 if (ale->type == ANIMTYPE_OBJECT)
1140                         continue;
1141                 
1142                 /* change the setting */
1143                 ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, vis);
1144                 
1145                 /* now, also flush selection status up/down as appropriate */
1146                 ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, (vis == ACHANNEL_SETFLAG_ADD));
1147         }
1148         
1149         /* cleanup */
1150         BLI_freelistN(&anim_data);
1151         BLI_freelistN(&all_data);
1152         
1153         /* send notifier that things have changed */
1154         WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1155         
1156         return OPERATOR_FINISHED;
1157 }
1158
1159 void ANIM_OT_channels_visibility_toggle (wmOperatorType *ot)
1160 {
1161         /* identifiers */
1162         ot->name= "Toggle Visibility";
1163         ot->idname= "ANIM_OT_channels_visibility_toggle";
1164         ot->description= "Toggle visibility in Graph Editor of all selected animation channels";
1165         
1166         /* api callbacks */
1167         ot->exec= animchannels_visibility_toggle_exec;
1168         ot->poll= ED_operator_ipo_active;
1169         
1170         /* flags */
1171         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1172 }
1173
1174 /* ********************** Set Flags Operator *********************** */
1175
1176 /* defines for setting animation-channel flags */
1177 EnumPropertyItem prop_animchannel_setflag_types[] = {
1178         {ACHANNEL_SETFLAG_TOGGLE, "TOGGLE", 0, "Toggle", ""},
1179         {ACHANNEL_SETFLAG_CLEAR, "DISABLE", 0, "Disable", ""},
1180         {ACHANNEL_SETFLAG_ADD, "ENABLE", 0, "Enable", ""},
1181         {ACHANNEL_SETFLAG_INVERT, "INVERT", 0, "Invert", ""},
1182         {0, NULL, 0, NULL, NULL}
1183 };
1184
1185 /* defines for set animation-channel settings */
1186 // TODO: could add some more types, but those are really quite dependent on the mode...
1187 EnumPropertyItem prop_animchannel_settings_types[] = {
1188         {ACHANNEL_SETTING_PROTECT, "PROTECT", 0, "Protect", ""},
1189         {ACHANNEL_SETTING_MUTE, "MUTE", 0, "Mute", ""},
1190         {0, NULL, 0, NULL, NULL}
1191 };
1192
1193
1194 /* ------------------- */
1195
1196 /* macro to be used in setflag_anim_channels */
1197 #define ASUBCHANNEL_SEL_OK(ale) ( (onlysel == 0) || \
1198                 ((ale->id) && (GS(ale->id->name)==ID_OB) && (((Object *)ale->id)->flag & SELECT)) ) 
1199
1200 /* Set/clear a particular flag (setting) for all selected + visible channels 
1201  *      setting: the setting to modify
1202  *      mode: eAnimChannels_SetFlag
1203  *      onlysel: only selected channels get the flag set
1204  */
1205 // TODO: enable a setting which turns flushing on/off?
1206 static void setflag_anim_channels (bAnimContext *ac, short setting, short mode, short onlysel, short flush)
1207 {
1208         ListBase anim_data = {NULL, NULL};
1209         ListBase all_data = {NULL, NULL};
1210         bAnimListElem *ale;
1211         int filter;
1212         
1213         /* filter data that we need if flush is on */
1214         if (flush) {
1215                 /* get list of all channels that selection may need to be flushed to */
1216                 filter= ANIMFILTER_CHANNELS;
1217                 ANIM_animdata_filter(ac, &all_data, filter, ac->data, ac->datatype);
1218         }
1219         
1220         /* filter data that we're working on */
1221         // XXX: noduplis enabled so that results don't cancel, but will be problematic for some channels where only type differs
1222         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS | ANIMFILTER_NODUPLIS);
1223         if (onlysel) filter |= ANIMFILTER_SEL;
1224         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1225         
1226         /* if toggling, check if disable or enable */
1227         if (mode == ACHANNEL_SETFLAG_TOGGLE) {
1228                 /* default to turn all on, unless we encounter one that's on... */
1229                 mode= ACHANNEL_SETFLAG_ADD;
1230                 
1231                 /* see if we should turn off instead... */
1232                 for (ale= anim_data.first; ale; ale= ale->next) {
1233                         /* set the setting in the appropriate way (if available) */
1234                         if (ANIM_channel_setting_get(ac, ale, setting) > 0) {
1235                                 mode= ACHANNEL_SETFLAG_CLEAR;
1236                                 break;
1237                         }
1238                 }
1239         }
1240         
1241         /* apply the setting */
1242         for (ale= anim_data.first; ale; ale= ale->next) {
1243                 /* skip channel if setting is not available */
1244                 if (ANIM_channel_setting_get(ac, ale, setting) == -1)
1245                         continue;
1246                 
1247                 /* set the setting in the appropriate way */
1248                 ANIM_channel_setting_set(ac, ale, setting, mode);
1249                 
1250                 /* if flush status... */
1251                 if (flush)
1252                         ANIM_flush_setting_anim_channels(ac, &all_data, ale, setting, mode);
1253         }
1254         
1255         BLI_freelistN(&anim_data);
1256         BLI_freelistN(&all_data);
1257 }
1258
1259 /* ------------------- */
1260
1261 static int animchannels_setflag_exec(bContext *C, wmOperator *op)
1262 {
1263         bAnimContext ac;
1264         short mode, setting;
1265         short flush=1;
1266         
1267         /* get editor data */
1268         if (ANIM_animdata_get_context(C, &ac) == 0)
1269                 return OPERATOR_CANCELLED;
1270                 
1271         /* mode (eAnimChannels_SetFlag), setting (eAnimChannel_Settings) */
1272         mode= RNA_enum_get(op->ptr, "mode");
1273         setting= RNA_enum_get(op->ptr, "type");
1274         
1275         /* check if setting is flushable */
1276         if (setting == ACHANNEL_SETTING_EXPAND)
1277                 flush= 0;
1278         
1279         /* modify setting 
1280          *      - only selected channels are affected
1281          */
1282         setflag_anim_channels(&ac, setting, mode, 1, flush);
1283         
1284         /* send notifier that things have changed */
1285         WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1286         
1287         return OPERATOR_FINISHED;
1288 }
1289
1290
1291 void ANIM_OT_channels_setting_enable (wmOperatorType *ot)
1292 {
1293         /* identifiers */
1294         ot->name= "Enable Channel Setting";
1295         ot->idname= "ANIM_OT_channels_setting_enable";
1296         ot->description= "Enable specified setting on all selected animation channels";
1297         
1298         /* api callbacks */
1299         ot->invoke= WM_menu_invoke;
1300         ot->exec= animchannels_setflag_exec;
1301         ot->poll= animedit_poll_channels_active;
1302         
1303         /* flags */
1304         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1305         
1306         /* props */
1307                 /* flag-setting mode */
1308         RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_ADD, "Mode", "");
1309                 /* setting to set */
1310         ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
1311 }
1312
1313 void ANIM_OT_channels_setting_disable (wmOperatorType *ot)
1314 {
1315         /* identifiers */
1316         ot->name= "Disable Channel Setting";
1317         ot->idname= "ANIM_OT_channels_setting_disable";
1318         ot->description= "Disable specified setting on all selected animation channels";
1319         
1320         /* api callbacks */
1321         ot->invoke= WM_menu_invoke;
1322         ot->exec= animchannels_setflag_exec;
1323         ot->poll= animedit_poll_channels_active;
1324         
1325         /* flags */
1326         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1327         
1328         /* props */
1329                 /* flag-setting mode */
1330         RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_CLEAR, "Mode", "");
1331                 /* setting to set */
1332         ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
1333 }
1334
1335 void ANIM_OT_channels_setting_invert (wmOperatorType *ot)
1336 {
1337         /* identifiers */
1338         ot->name= "Invert Channel Setting";
1339         ot->idname= "ANIM_OT_channels_setting_toggle";
1340         ot->description= "Invert specified setting on all selected animation channels";
1341         
1342         /* api callbacks */
1343         ot->invoke= WM_menu_invoke;
1344         ot->exec= animchannels_setflag_exec;
1345         ot->poll= animedit_poll_channels_active;
1346         
1347         /* flags */
1348         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1349         
1350         /* props */
1351                 /* flag-setting mode */
1352         RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_INVERT, "Mode", "");
1353                 /* setting to set */
1354         ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
1355 }
1356
1357 void ANIM_OT_channels_setting_toggle (wmOperatorType *ot)
1358 {
1359         /* identifiers */
1360         ot->name= "Toggle Channel Setting";
1361         ot->idname= "ANIM_OT_channels_setting_toggle";
1362         ot->description= "Toggle specified setting on all selected animation channels";
1363         
1364         /* api callbacks */
1365         ot->invoke= WM_menu_invoke;
1366         ot->exec= animchannels_setflag_exec;
1367         ot->poll= animedit_poll_channels_active;
1368         
1369         /* flags */
1370         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1371         
1372         /* props */
1373                 /* flag-setting mode */
1374         RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", "");
1375                 /* setting to set */
1376         ot->prop= RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
1377 }
1378
1379 void ANIM_OT_channels_editable_toggle (wmOperatorType *ot)
1380 {
1381         /* identifiers */
1382         ot->name= "Toggle Channel Editability";
1383         ot->idname= "ANIM_OT_channels_editable_toggle";
1384         ot->description= "Toggle editability of selected channels";
1385         
1386         /* api callbacks */
1387         ot->exec= animchannels_setflag_exec;
1388         ot->poll= animedit_poll_channels_active;
1389         
1390         /* flags */
1391         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1392         
1393         /* props */
1394                 /* flag-setting mode */
1395         RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", "");
1396                 /* setting to set */
1397         RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, ACHANNEL_SETTING_PROTECT, "Type", "");
1398 }
1399
1400 /* ********************** Expand Channels Operator *********************** */
1401
1402 static int animchannels_expand_exec (bContext *C, wmOperator *op)
1403 {
1404         bAnimContext ac;
1405         short onlysel= 1;
1406         
1407         /* get editor data */
1408         if (ANIM_animdata_get_context(C, &ac) == 0)
1409                 return OPERATOR_CANCELLED;
1410                 
1411         /* only affect selected channels? */
1412         if (RNA_boolean_get(op->ptr, "all"))
1413                 onlysel= 0;
1414         
1415         /* modify setting */
1416         setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_ADD, onlysel, 0);
1417         
1418         /* send notifier that things have changed */
1419         WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1420         
1421         return OPERATOR_FINISHED;
1422 }
1423
1424 void ANIM_OT_channels_expand (wmOperatorType *ot)
1425 {
1426         /* identifiers */
1427         ot->name= "Expand Channels";
1428         ot->idname= "ANIM_OT_channels_expand";
1429         ot->description= "Expand (i.e. open) all selected expandable animation channels";
1430         
1431         /* api callbacks */
1432         ot->exec= animchannels_expand_exec;
1433         ot->poll= animedit_poll_channels_active;
1434         
1435         /* flags */
1436         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1437         
1438         /* props */
1439         ot->prop= RNA_def_boolean(ot->srna, "all", 1, "All", "Expand all channels (not just selected ones)");
1440 }
1441
1442 /* ********************** Collapse Channels Operator *********************** */
1443
1444 static int animchannels_collapse_exec (bContext *C, wmOperator *op)
1445 {
1446         bAnimContext ac;
1447         short onlysel= 1;
1448         
1449         /* get editor data */
1450         if (ANIM_animdata_get_context(C, &ac) == 0)
1451                 return OPERATOR_CANCELLED;
1452                 
1453         /* only affect selected channels? */
1454         if (RNA_boolean_get(op->ptr, "all"))
1455                 onlysel= 0;
1456         
1457         /* modify setting */
1458         setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_CLEAR, onlysel, 0);
1459         
1460         /* send notifier that things have changed */
1461         WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_EDITED, NULL);
1462         
1463         return OPERATOR_FINISHED;
1464 }
1465
1466 void ANIM_OT_channels_collapse (wmOperatorType *ot)
1467 {
1468         /* identifiers */
1469         ot->name= "Collapse Channels";
1470         ot->idname= "ANIM_OT_channels_collapse";
1471         ot->description= "Collapse (i.e. close) all selected expandable animation channels";
1472         
1473         /* api callbacks */
1474         ot->exec= animchannels_collapse_exec;
1475         ot->poll= animedit_poll_channels_active;
1476         
1477         /* flags */
1478         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1479         
1480         /* props */
1481         ot->prop= RNA_def_boolean(ot->srna, "all", 1, "All", "Collapse all channels (not just selected ones)");
1482 }
1483
1484 /* ********************** Select All Operator *********************** */
1485
1486 static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
1487 {
1488         bAnimContext ac;
1489         
1490         /* get editor data */
1491         if (ANIM_animdata_get_context(C, &ac) == 0)
1492                 return OPERATOR_CANCELLED;
1493                 
1494         /* 'standard' behaviour - check if selected, then apply relevant selection */
1495         if (RNA_boolean_get(op->ptr, "invert"))
1496                 ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 0, ACHANNEL_SETFLAG_TOGGLE);
1497         else
1498                 ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_ADD);
1499         
1500         /* send notifier that things have changed */
1501         WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_SELECTED, NULL);
1502         
1503         return OPERATOR_FINISHED;
1504 }
1505  
1506 void ANIM_OT_channels_select_all_toggle (wmOperatorType *ot)
1507 {
1508         /* identifiers */
1509         ot->name= "Select All";
1510         ot->idname= "ANIM_OT_channels_select_all_toggle";
1511         ot->description= "Toggle selection of all animation channels";
1512         
1513         /* api callbacks */
1514         ot->exec= animchannels_deselectall_exec;
1515         ot->poll= animedit_poll_channels_nla_tweakmode_off;
1516         
1517         /* flags */
1518         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1519         
1520         /* props */
1521         ot->prop= RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
1522 }
1523
1524 /* ******************** Borderselect Operator *********************** */
1525
1526 static void borderselect_anim_channels (bAnimContext *ac, rcti *rect, short selectmode)
1527 {
1528         ListBase anim_data = {NULL, NULL};
1529         bAnimListElem *ale;
1530         int filter;
1531         
1532         View2D *v2d= &ac->ar->v2d;
1533         rctf rectf;
1534         float ymin=0, ymax=(float)(-ACHANNEL_HEIGHT);
1535         
1536         /* convert border-region to view coordinates */
1537         UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin+2, &rectf.xmin, &rectf.ymin);
1538         UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax-2, &rectf.xmax, &rectf.ymax);
1539         
1540         /* filter data */
1541         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
1542         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1543         
1544         /* loop over data, doing border select */
1545         for (ale= anim_data.first; ale; ale= ale->next) {
1546                 ymin= ymax - ACHANNEL_STEP;
1547                 
1548                 /* if channel is within border-select region, alter it */
1549                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
1550                         /* set selection flags only */
1551                         ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, selectmode);
1552                         
1553                         /* type specific actions */
1554                         switch (ale->type) {
1555                                 case ANIMTYPE_GROUP:
1556                                 {
1557                                         bActionGroup *agrp= (bActionGroup *)ale->data;
1558                                         
1559                                         /* always clear active flag after doing this */
1560                                         agrp->flag &= ~AGRP_ACTIVE;
1561                                 }
1562                                         break;
1563                         }
1564                 }
1565                 
1566                 /* set minimum extent to be the maximum of the next channel */
1567                 ymax= ymin;
1568         }
1569         
1570         /* cleanup */
1571         BLI_freelistN(&anim_data);
1572 }
1573
1574 /* ------------------- */
1575
1576 static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
1577 {
1578         bAnimContext ac;
1579         rcti rect;
1580         short selectmode=0;
1581         int gesture_mode;
1582         
1583         /* get editor data */
1584         if (ANIM_animdata_get_context(C, &ac) == 0)
1585                 return OPERATOR_CANCELLED;
1586         
1587         /* get settings from operator */
1588         rect.xmin= RNA_int_get(op->ptr, "xmin");
1589         rect.ymin= RNA_int_get(op->ptr, "ymin");
1590         rect.xmax= RNA_int_get(op->ptr, "xmax");
1591         rect.ymax= RNA_int_get(op->ptr, "ymax");
1592                 
1593         gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
1594         if (gesture_mode == GESTURE_MODAL_SELECT)
1595                 selectmode = ACHANNEL_SETFLAG_ADD;
1596         else
1597                 selectmode = ACHANNEL_SETFLAG_CLEAR;
1598         
1599         /* apply borderselect animation channels */
1600         borderselect_anim_channels(&ac, &rect, selectmode);
1601         
1602         /* send notifier that things have changed */
1603         WM_event_add_notifier(C, NC_ANIMATION|ND_ANIMCHAN|NA_SELECTED, NULL);
1604         
1605         return OPERATOR_FINISHED;
1606
1607
1608 void ANIM_OT_channels_select_border(wmOperatorType *ot)
1609 {
1610         /* identifiers */
1611         ot->name= "Border Select";
1612         ot->idname= "ANIM_OT_channels_select_border";
1613         ot->description= "Select all animation channels within the specified region";
1614         
1615         /* api callbacks */
1616         ot->invoke= WM_border_select_invoke;
1617         ot->exec= animchannels_borderselect_exec;
1618         ot->modal= WM_border_select_modal;
1619         
1620         ot->poll= animedit_poll_channels_nla_tweakmode_off;
1621         
1622         /* flags */
1623         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1624         
1625         /* rna */
1626         WM_operator_properties_gesture_border(ot, FALSE);
1627 }
1628
1629 /* ******************** Mouse-Click Operator *********************** */
1630 /* Handle selection changes due to clicking on channels. Settings will get caught by UI code... */
1631
1632 static int mouse_anim_channels (bAnimContext *ac, float x, int channel_index, short selectmode)
1633 {
1634         ListBase anim_data = {NULL, NULL};
1635         bAnimListElem *ale;
1636         int filter;
1637         int notifierFlags = 0;
1638         
1639         /* get the channel that was clicked on */
1640                 /* filter channels */
1641         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
1642         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1643         
1644                 /* get channel from index */
1645         ale= BLI_findlink(&anim_data, channel_index);
1646         if (ale == NULL) {
1647                 /* channel not found */
1648                 if (G.f & G_DEBUG)
1649                         printf("Error: animation channel (index = %d) not found in mouse_anim_channels() \n", channel_index);
1650                 
1651                 BLI_freelistN(&anim_data);
1652                 return 0;
1653         }
1654         
1655         /* selectmode -1 is a special case for ActionGroups only, which selects all of the channels underneath it only... */
1656         // TODO: should this feature be extended to work with other channel types too?
1657         if ((selectmode == -1) && (ale->type != ANIMTYPE_GROUP)) {
1658                 /* normal channels should not behave normally in this case */
1659                 BLI_freelistN(&anim_data);
1660                 return 0;
1661         }
1662         
1663         /* action to take depends on what channel we've got */
1664         // WARNING: must keep this in sync with the equivalent function in nla_channels.c
1665         switch (ale->type) {
1666                 case ANIMTYPE_SCENE:
1667                 {
1668                         Scene *sce= (Scene *)ale->data;
1669                         AnimData *adt= sce->adt;
1670                         
1671                         /* set selection status */
1672                         if (selectmode == SELECT_INVERT) {
1673                                 /* swap select */
1674                                 sce->flag ^= SCE_DS_SELECTED;
1675                                 if (adt) adt->flag ^= ADT_UI_SELECTED;
1676                         }
1677                         else {
1678                                 sce->flag |= SCE_DS_SELECTED;
1679                                 if (adt) adt->flag |= ADT_UI_SELECTED;
1680                         }
1681                         
1682                         notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
1683                 }
1684                         break;
1685                 case ANIMTYPE_OBJECT:
1686                 {
1687                         bDopeSheet *ads= (bDopeSheet *)ac->data;
1688                         Scene *sce= (Scene *)ads->source;
1689                         Base *base= (Base *)ale->data;
1690                         Object *ob= base->object;
1691                         AnimData *adt= ob->adt;
1692                         
1693                         /* set selection status */
1694                         if (selectmode == SELECT_INVERT) {
1695                                 /* swap select */
1696                                 base->flag ^= SELECT;
1697                                 ob->flag= base->flag;
1698                                 
1699                                 if (adt) adt->flag ^= ADT_UI_SELECTED;
1700                         }
1701                         else {
1702                                 Base *b;
1703                                 
1704                                 /* deselect all */
1705                                 // TODO: should this deselect all other types of channels too?
1706                                 for (b= sce->base.first; b; b= b->next) {
1707                                         b->flag &= ~SELECT;
1708                                         b->object->flag= b->flag;
1709                                         if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED|ADT_UI_ACTIVE);
1710                                 }
1711                                 
1712                                 /* select object now */
1713                                 base->flag |= SELECT;
1714                                 ob->flag |= SELECT;
1715                                 if (adt) adt->flag |= ADT_UI_SELECTED;
1716                         }
1717                         
1718                         if ((adt) && (adt->flag & ADT_UI_SELECTED))
1719                                 adt->flag |= ADT_UI_ACTIVE;
1720                         
1721                         notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
1722                 }
1723                         break;
1724                 
1725                 case ANIMTYPE_FILLACTD: /* Action Expander */
1726                 case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
1727                 case ANIMTYPE_DSLAM:
1728                 case ANIMTYPE_DSCAM:
1729                 case ANIMTYPE_DSCUR:
1730                 case ANIMTYPE_DSSKEY:
1731                 case ANIMTYPE_DSWOR:
1732                 case ANIMTYPE_DSPART:
1733                 case ANIMTYPE_DSMBALL:
1734                 case ANIMTYPE_DSARM:
1735                 case ANIMTYPE_DSMESH:
1736                 case ANIMTYPE_DSNTREE:
1737                 case ANIMTYPE_DSTEX:
1738                 case ANIMTYPE_DSLINESTYLE:
1739                 {
1740                         /* sanity checking... */
1741                         if (ale->adt) {
1742                                 /* select/deselect */
1743                                 if (selectmode == SELECT_INVERT) {
1744                                         /* inverse selection status of this AnimData block only */
1745                                         ale->adt->flag ^= ADT_UI_SELECTED;
1746                                 }
1747                                 else {
1748                                         /* select AnimData block by itself */
1749                                         ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1750                                         ale->adt->flag |= ADT_UI_SELECTED;
1751                                 }
1752                                 
1753                                 /* set active? */
1754                                 if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
1755                                         ale->adt->flag |= ADT_UI_ACTIVE;
1756                         }
1757                         
1758                         notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
1759                 }       
1760                         break;
1761                 
1762                 case ANIMTYPE_GROUP: 
1763                 {
1764                         bActionGroup *agrp= (bActionGroup *)ale->data;
1765                         
1766                         /* select/deselect group */
1767                         if (selectmode == SELECT_INVERT) {
1768                                 /* inverse selection status of this group only */
1769                                 agrp->flag ^= AGRP_SELECTED;
1770                         }
1771                         else if (selectmode == -1) {
1772                                 /* select all in group (and deselect everthing else) */ 
1773                                 FCurve *fcu;
1774                                 
1775                                 /* deselect all other channels */
1776                                 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1777                                 
1778                                 /* only select channels in group and group itself */
1779                                 for (fcu= agrp->channels.first; fcu && fcu->grp==agrp; fcu= fcu->next)
1780                                         fcu->flag |= FCURVE_SELECTED;
1781                                 agrp->flag |= AGRP_SELECTED;                                    
1782                         }
1783                         else {
1784                                 /* select group by itself */
1785                                 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1786                                 agrp->flag |= AGRP_SELECTED;
1787                         }
1788                         
1789                         /* if group is selected now, make group the 'active' one in the visible list */
1790                         if (agrp->flag & AGRP_SELECTED)
1791                                 ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
1792                                 
1793                         notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
1794                 }
1795                         break;
1796                 case ANIMTYPE_FCURVE: 
1797                 {
1798                         FCurve *fcu= (FCurve *)ale->data;
1799                         
1800                         /* select/deselect */
1801                         if (selectmode == SELECT_INVERT) {
1802                                 /* inverse selection status of this F-Curve only */
1803                                 fcu->flag ^= FCURVE_SELECTED;
1804                         }
1805                         else {
1806                                 /* select F-Curve by itself */
1807                                 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1808                                 fcu->flag |= FCURVE_SELECTED;
1809                         }
1810                         
1811                         /* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */
1812                         if (fcu->flag & FCURVE_SELECTED)
1813                                 ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ANIMTYPE_FCURVE);
1814                                 
1815                         notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
1816                 }
1817                         break;
1818                 case ANIMTYPE_SHAPEKEY: 
1819                 {
1820                         KeyBlock *kb= (KeyBlock *)ale->data;
1821                         
1822                         /* select/deselect */
1823                         if (selectmode == SELECT_INVERT) {
1824                                 /* inverse selection status of this ShapeKey only */
1825                                 kb->flag ^= KEYBLOCK_SEL;
1826                         }
1827                         else {
1828                                 /* select ShapeKey by itself */
1829                                 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
1830                                 kb->flag |= KEYBLOCK_SEL;
1831                         }
1832                                 
1833                         notifierFlags |= (ND_ANIMCHAN|NA_SELECTED);
1834                 }
1835                         break;
1836                 case ANIMTYPE_GPDATABLOCK:
1837                 {
1838                         bGPdata *gpd= (bGPdata *)ale->data;
1839                         
1840                         /* toggle expand */
1841                         gpd->flag ^= GP_DATA_EXPAND;
1842                         
1843                         notifierFlags |= (ND_ANIMCHAN|NA_EDITED);
1844                 }
1845                         break;
1846                 case ANIMTYPE_GPLAYER:
1847                 {
1848 #if 0 // XXX future of this is unclear
1849                         bGPdata *gpd= (bGPdata *)ale->owner; // xxx depreceated
1850                         bGPDlayer *gpl= (bGPDlayer *)ale->data;
1851                         
1852                         if (x >= (ACHANNEL_NAMEWIDTH-16)) {
1853                                 /* toggle lock */
1854                                 gpl->flag ^= GP_LAYER_LOCKED;
1855                         }
1856                         else if (x >= (ACHANNEL_NAMEWIDTH-32)) {
1857                                 /* toggle hide */
1858                                 gpl->flag ^= GP_LAYER_HIDE;
1859                         }
1860                         else {
1861                                 /* select/deselect */
1862                                 //if (G.qual & LR_SHIFTKEY) {
1863                                         //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
1864                                 //}
1865                                 //else {
1866                                         //deselect_gpencil_layers(data, 0);
1867                                         //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
1868                                 //}
1869                         }
1870 #endif // XXX future of this is unclear
1871                 }
1872                         break;
1873                 default:
1874                         if (G.f & G_DEBUG)
1875                                 printf("Error: Invalid channel type in mouse_anim_channels() \n");
1876         }
1877         
1878         /* free channels */
1879         BLI_freelistN(&anim_data);
1880         
1881         /* return notifier flags */
1882         return notifierFlags;
1883 }
1884
1885 /* ------------------- */
1886
1887 /* handle clicking */
1888 static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event)
1889 {
1890         bAnimContext ac;
1891         Scene *scene;
1892         ARegion *ar;
1893         View2D *v2d;
1894         int mval[2], channel_index;
1895         int notifierFlags = 0;
1896         short selectmode;
1897         float x, y;
1898         
1899         
1900         /* get editor data */
1901         if (ANIM_animdata_get_context(C, &ac) == 0)
1902                 return OPERATOR_CANCELLED;
1903                 
1904         /* get useful pointers from animation context data */
1905         scene= ac.scene;
1906         ar= ac.ar;
1907         v2d= &ar->v2d;
1908         
1909         /* get mouse coordinates (in region coordinates) */
1910         mval[0]= (event->x - ar->winrct.xmin);
1911         mval[1]= (event->y - ar->winrct.ymin);
1912         
1913         /* select mode is either replace (deselect all, then add) or add/extend */
1914         if (RNA_boolean_get(op->ptr, "extend"))
1915                 selectmode= SELECT_INVERT;
1916         else if (RNA_boolean_get(op->ptr, "children_only"))
1917                 selectmode= -1; /* this is a bit of a special case for ActionGroups only... should it be removed or extended to all instead? */
1918         else
1919                 selectmode= SELECT_REPLACE;
1920         
1921         /* figure out which channel user clicked in 
1922          * Note: although channels technically start at y= ACHANNEL_FIRST, we need to adjust by half a channel's height
1923          *              so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
1924          *              ACHANNEL_HEIGHT_HALF.
1925          */
1926         UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
1927         UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
1928         
1929         /* handle mouse-click in the relevant channel then */
1930         notifierFlags= mouse_anim_channels(&ac, x, channel_index, selectmode);
1931         
1932         /* set notifier that things have changed */
1933         WM_event_add_notifier(C, NC_ANIMATION|notifierFlags, NULL);
1934         
1935         return OPERATOR_FINISHED;
1936 }
1937  
1938 void ANIM_OT_channels_click (wmOperatorType *ot)
1939 {
1940         /* identifiers */
1941         ot->name= "Mouse Click on Channels";
1942         ot->idname= "ANIM_OT_channels_click";
1943         ot->description= "Handle mouse-clicks over animation channels";
1944         
1945         /* api callbacks */
1946         ot->invoke= animchannels_mouseclick_invoke;
1947         ot->poll= animedit_poll_channels_active;
1948         
1949         /* flags */
1950         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1951         
1952         /* id-props */
1953         RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
1954         RNA_def_boolean(ot->srna, "children_only", 0, "Select Children Only", ""); // CTRLKEY|SHIFTKEY
1955 }
1956
1957 /* ************************************************************************** */
1958 /* Operator Registration */
1959
1960 void ED_operatortypes_animchannels(void)
1961 {
1962         WM_operatortype_append(ANIM_OT_channels_select_all_toggle);
1963         WM_operatortype_append(ANIM_OT_channels_select_border);
1964         WM_operatortype_append(ANIM_OT_channels_click);
1965         
1966         WM_operatortype_append(ANIM_OT_channels_setting_enable);
1967         WM_operatortype_append(ANIM_OT_channels_setting_disable);
1968         WM_operatortype_append(ANIM_OT_channels_setting_invert);
1969         WM_operatortype_append(ANIM_OT_channels_setting_toggle);
1970         
1971         WM_operatortype_append(ANIM_OT_channels_delete);
1972         
1973                 // XXX does this need to be a separate operator?
1974         WM_operatortype_append(ANIM_OT_channels_editable_toggle);
1975         
1976                 // XXX these need to be updated for new system... todo...
1977         //WM_operatortype_append(ANIM_OT_channels_move_up);
1978         //WM_operatortype_append(ANIM_OT_channels_move_down);
1979         //WM_operatortype_append(ANIM_OT_channels_move_top);
1980         //WM_operatortype_append(ANIM_OT_channels_move_bottom);
1981         
1982         WM_operatortype_append(ANIM_OT_channels_expand);
1983         WM_operatortype_append(ANIM_OT_channels_collapse);
1984         
1985         WM_operatortype_append(ANIM_OT_channels_visibility_toggle);
1986         WM_operatortype_append(ANIM_OT_channels_visibility_set);
1987 }
1988
1989 // TODO: check on a poll callback for this, to get hotkeys into menus
1990 void ED_keymap_animchannels(wmKeyConfig *keyconf)
1991 {
1992         wmKeyMap *keymap = WM_keymap_find(keyconf, "Animation Channels", 0, 0);
1993         
1994         /* selection */
1995                 /* click-select */
1996                 // XXX for now, only leftmouse.... 
1997         WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, 0, 0);
1998         RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1);
1999         RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, KM_CTRL|KM_SHIFT, 0)->ptr, "children_only", 1);
2000         
2001                 /* deselect all */
2002         WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", AKEY, KM_PRESS, 0, 0);
2003         RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
2004         
2005                 /* borderselect */
2006         WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", BKEY, KM_PRESS, 0, 0);
2007         WM_keymap_add_item(keymap, "ANIM_OT_channels_select_border", EVT_TWEAK_L, KM_ANY, 0, 0);
2008         
2009         /* delete */
2010         WM_keymap_add_item(keymap, "ANIM_OT_channels_delete", XKEY, KM_PRESS, 0, 0);
2011         WM_keymap_add_item(keymap, "ANIM_OT_channels_delete", DELKEY, KM_PRESS, 0, 0);
2012         
2013         /* settings */
2014         WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_toggle", WKEY, KM_PRESS, KM_SHIFT, 0);
2015         WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_enable", WKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
2016         WM_keymap_add_item(keymap, "ANIM_OT_channels_setting_disable", WKEY, KM_PRESS, KM_ALT, 0);
2017         
2018         /* settings - specialised hotkeys */
2019         WM_keymap_add_item(keymap, "ANIM_OT_channels_editable_toggle", TABKEY, KM_PRESS, 0, 0);
2020         
2021         /* expand/collapse */
2022         WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, 0, 0);
2023         WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, 0, 0);
2024         
2025         RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_expand", PADPLUSKEY, KM_PRESS, KM_CTRL, 0)->ptr, "all", 0);
2026         RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_collapse", PADMINUS, KM_PRESS, KM_CTRL, 0)->ptr, "all", 0);
2027         
2028         /* rearranging - actions only */
2029         //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_up", PAGEUPKEY, KM_PRESS, KM_SHIFT, 0);
2030         //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_down", PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0);
2031         //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_to_top", PAGEUPKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
2032         //WM_keymap_add_item(keymap, "ANIM_OT_channels_move_to_bottom", PAGEDOWNKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0);
2033         
2034         /* Graph Editor only */
2035         WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_set", VKEY, KM_PRESS, 0, 0);
2036         WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_toggle", VKEY, KM_PRESS, KM_SHIFT, 0);
2037 }
2038
2039 /* ************************************************************************** */