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