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