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