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