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