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