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