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