WM: refactor gestures for use as tools
[blender.git] / source / blender / editors / animation / anim_channels_edit.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
19  * All rights reserved.
20  *
21  * Contributor(s): Joshua Leung
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/animation/anim_channels_edit.c
27  *  \ingroup edanimation
28  */
29
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h> 
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BKE_depsgraph.h"
38 #include "BLI_blenlib.h"
39 #include "BLI_utildefines.h"
40 #include "BLI_listbase.h"
41 #include "BKE_library.h"
42
43 #include "DNA_anim_types.h"
44 #include "DNA_object_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_key_types.h"
47 #include "DNA_gpencil_types.h"
48 #include "DNA_mask_types.h"
49
50 #include "RNA_access.h"
51 #include "RNA_define.h"
52
53 #include "BKE_animsys.h"
54 #include "BKE_action.h"
55 #include "BKE_fcurve.h"
56 #include "BKE_gpencil.h"
57 #include "BKE_context.h"
58 #include "BKE_mask.h"
59 #include "BKE_global.h"
60
61 #include "UI_view2d.h"
62
63 #include "ED_anim_api.h"
64 #include "ED_armature.h"
65 #include "ED_keyframes_edit.h" // XXX move the select modes out of there!
66 #include "ED_object.h"
67 #include "ED_screen.h"
68
69 #include "WM_api.h"
70 #include "WM_types.h"
71
72 /* ************************************************************************** */
73 /* CHANNELS API - Exposed API */
74
75 /* -------------------------- Selection ------------------------------------- */
76
77 /* Set the given animation-channel as the active one for the active context */
78 // TODO: extend for animdata types...
79 void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datatype, eAnimFilter_Flags filter, void *channel_data, eAnim_ChannelType channel_type)
80 {
81         ListBase anim_data = {NULL, NULL};
82         bAnimListElem *ale;
83         
84         /* try to build list of filtered items */
85         ANIM_animdata_filter(ac, &anim_data, filter, data, datatype);
86         if (BLI_listbase_is_empty(&anim_data))
87                 return;
88                 
89         /* only clear the 'active' flag for the channels of the same type */
90         for (ale = anim_data.first; ale; ale = ale->next) {
91                 /* skip if types don't match */
92                 if (channel_type != ale->type)
93                         continue;
94                 
95                 /* flag to set depends on type */
96                 switch (ale->type) {
97                         case ANIMTYPE_GROUP:
98                         {
99                                 bActionGroup *agrp = (bActionGroup *)ale->data;
100                                 
101                                 ACHANNEL_SET_FLAG(agrp, ACHANNEL_SETFLAG_CLEAR, AGRP_ACTIVE);
102                                 break;
103                         }
104                         case ANIMTYPE_FCURVE:
105                         case ANIMTYPE_NLACURVE:
106                         {
107                                 FCurve *fcu = (FCurve *)ale->data;
108                                 
109                                 ACHANNEL_SET_FLAG(fcu, ACHANNEL_SETFLAG_CLEAR, FCURVE_ACTIVE);
110                                 break;
111                         }
112                         case ANIMTYPE_NLATRACK:
113                         {
114                                 NlaTrack *nlt = (NlaTrack *)ale->data;
115                                 
116                                 ACHANNEL_SET_FLAG(nlt, ACHANNEL_SETFLAG_CLEAR, NLATRACK_ACTIVE);
117                                 break;
118                         }
119                         case ANIMTYPE_FILLACTD: /* Action Expander */
120                         case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
121                         case ANIMTYPE_DSLAM:
122                         case ANIMTYPE_DSCAM:
123                         case ANIMTYPE_DSCACHEFILE:
124                         case ANIMTYPE_DSCUR:
125                         case ANIMTYPE_DSSKEY:
126                         case ANIMTYPE_DSWOR:
127                         case ANIMTYPE_DSPART:
128                         case ANIMTYPE_DSMBALL:
129                         case ANIMTYPE_DSARM:
130                         case ANIMTYPE_DSMESH:
131                         case ANIMTYPE_DSTEX:
132                         case ANIMTYPE_DSLAT:
133                         case ANIMTYPE_DSLINESTYLE:
134                         case ANIMTYPE_DSSPK:
135                         case ANIMTYPE_DSGPENCIL:
136                         case ANIMTYPE_DSMCLIP:
137                         {
138                                 /* need to verify that this data is valid for now */
139                                 if (ale->adt) {
140                                         ACHANNEL_SET_FLAG(ale->adt, ACHANNEL_SETFLAG_CLEAR, ADT_UI_ACTIVE);
141                                 }
142                                 break;
143                         }
144                         case ANIMTYPE_GPLAYER:
145                         {
146                                 bGPDlayer *gpl = (bGPDlayer *)ale->data;
147                                 
148                                 ACHANNEL_SET_FLAG(gpl, ACHANNEL_SETFLAG_CLEAR, GP_LAYER_ACTIVE);
149                                 break;
150                         }
151                 }
152         }
153         
154         /* set active flag */
155         if (channel_data) {
156                 switch (channel_type) {
157                         case ANIMTYPE_GROUP:
158                         {
159                                 bActionGroup *agrp = (bActionGroup *)channel_data;
160                                 agrp->flag |= AGRP_ACTIVE;
161                                 break;
162                         }
163                         case ANIMTYPE_FCURVE:
164                         case ANIMTYPE_NLACURVE:
165                         {
166                                 FCurve *fcu = (FCurve *)channel_data;
167                                 fcu->flag |= FCURVE_ACTIVE;
168                                 break;
169                         }
170                         case ANIMTYPE_NLATRACK:
171                         {
172                                 NlaTrack *nlt = (NlaTrack *)channel_data;
173                                 nlt->flag |= NLATRACK_ACTIVE;
174                                 break;
175                         }
176                         case ANIMTYPE_FILLACTD: /* Action Expander */
177                         case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
178                         case ANIMTYPE_DSLAM:
179                         case ANIMTYPE_DSCAM:
180                         case ANIMTYPE_DSCACHEFILE:
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                         case ANIMTYPE_DSMESH:
188                         case ANIMTYPE_DSLAT:
189                         case ANIMTYPE_DSLINESTYLE:
190                         case ANIMTYPE_DSSPK:
191                         case ANIMTYPE_DSNTREE:
192                         case ANIMTYPE_DSTEX:
193                         case ANIMTYPE_DSGPENCIL:
194                         case ANIMTYPE_DSMCLIP:
195                         {
196                                 /* need to verify that this data is valid for now */
197                                 if (ale && ale->adt) {
198                                         ale->adt->flag |= ADT_UI_ACTIVE;
199                                 }
200                                 break;
201                         }
202                         
203                         case ANIMTYPE_GPLAYER:
204                         {
205                                 bGPDlayer *gpl = (bGPDlayer *)channel_data;
206                                 gpl->flag |= GP_LAYER_ACTIVE;
207                                 break;
208                         }
209                         
210                         /* unhandled currently, but may be interesting */
211                         case ANIMTYPE_MASKLAYER:
212                         case ANIMTYPE_SHAPEKEY:
213                         case ANIMTYPE_NLAACTION:
214                                 break;
215                         
216                         /* other types */
217                         default:
218                                 break;
219                 }
220         }
221         
222         /* clean up */
223         ANIM_animdata_freelist(&anim_data);
224 }
225
226 /* Deselect all animation channels 
227  *      - data: pointer to datatype, as contained in bAnimContext
228  *      - datatype: the type of data that 'data' represents (eAnimCont_Types)
229  *      - test: check if deselecting instead of selecting
230  *      - sel: eAnimChannels_SetFlag;
231  */
232 void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types datatype, bool test, eAnimChannels_SetFlag sel)
233 {
234         ListBase anim_data = {NULL, NULL};
235         bAnimListElem *ale;
236         int filter;
237         
238         /* filter data */
239         /* NOTE: no list visible, otherwise, we get dangling */
240         filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS;
241         ANIM_animdata_filter(ac, &anim_data, filter, data, datatype);
242         
243         /* See if we should be selecting or deselecting */
244         if (test) {
245                 for (ale = anim_data.first; ale; ale = ale->next) {
246                         if (sel == 0) 
247                                 break;
248                         
249                         switch (ale->type) {
250                                 case ANIMTYPE_SCENE:
251                                         if (ale->flag & SCE_DS_SELECTED)
252                                                 sel = ACHANNEL_SETFLAG_CLEAR;
253                                         break;
254                                 case ANIMTYPE_OBJECT:
255 #if 0   /* for now, do not take object selection into account, since it gets too annoying */
256                                         if (ale->flag & SELECT)
257                                                 sel = ACHANNEL_SETFLAG_CLEAR;
258 #endif
259                                         break;
260                                 case ANIMTYPE_GROUP:
261                                         if (ale->flag & AGRP_SELECTED)
262                                                 sel = ACHANNEL_SETFLAG_CLEAR;
263                                         break;
264                                 case ANIMTYPE_FCURVE:
265                                 case ANIMTYPE_NLACURVE:
266                                         if (ale->flag & FCURVE_SELECTED)
267                                                 sel = ACHANNEL_SETFLAG_CLEAR;
268                                         break;
269                                 case ANIMTYPE_SHAPEKEY:
270                                         if (ale->flag & KEYBLOCK_SEL)
271                                                 sel = ACHANNEL_SETFLAG_CLEAR;
272                                         break;
273                                 case ANIMTYPE_NLATRACK:
274                                         if (ale->flag & NLATRACK_SELECTED)
275                                                 sel = ACHANNEL_SETFLAG_CLEAR;
276                                         break;
277                                         
278                                 case ANIMTYPE_FILLACTD: /* Action Expander */
279                                 case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
280                                 case ANIMTYPE_DSLAM:
281                                 case ANIMTYPE_DSCAM:
282                                 case ANIMTYPE_DSCACHEFILE:
283                                 case ANIMTYPE_DSCUR:
284                                 case ANIMTYPE_DSSKEY:
285                                 case ANIMTYPE_DSWOR:
286                                 case ANIMTYPE_DSPART:
287                                 case ANIMTYPE_DSMBALL:
288                                 case ANIMTYPE_DSARM:
289                                 case ANIMTYPE_DSMESH:
290                                 case ANIMTYPE_DSNTREE:
291                                 case ANIMTYPE_DSTEX:
292                                 case ANIMTYPE_DSLAT:
293                                 case ANIMTYPE_DSLINESTYLE:
294                                 case ANIMTYPE_DSSPK:
295                                 case ANIMTYPE_DSGPENCIL:
296                                 case ANIMTYPE_DSMCLIP:
297                                 {
298                                         if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
299                                                 sel = ACHANNEL_SETFLAG_CLEAR;
300                                         break;
301                                 }
302                                 case ANIMTYPE_GPLAYER:
303                                         if (ale->flag & GP_LAYER_SELECT)
304                                                 sel = ACHANNEL_SETFLAG_CLEAR;
305                                         break;
306                                 case ANIMTYPE_MASKLAYER:
307                                         if (ale->flag & MASK_LAYERFLAG_SELECT)
308                                                 sel = ACHANNEL_SETFLAG_CLEAR;
309                                         break;
310                         }
311                 }
312         }
313                 
314         /* Now set the flags */
315         for (ale = anim_data.first; ale; ale = ale->next) {
316                 switch (ale->type) {
317                         case ANIMTYPE_SCENE:
318                         {
319                                 Scene *scene = (Scene *)ale->data;
320                                 
321                                 ACHANNEL_SET_FLAG(scene, sel, SCE_DS_SELECTED);
322                                 
323                                 if (scene->adt) {
324                                         ACHANNEL_SET_FLAG(scene, sel, ADT_UI_SELECTED);
325                                 }
326                                 break;
327                         }
328                         case ANIMTYPE_OBJECT:
329                         {
330 #if 0   /* for now, do not take object selection into account, since it gets too annoying */
331                                 Base *base = (Base *)ale->data;
332                                 Object *ob = base->object;
333
334                                 ACHANNEL_SET_FLAG(base, sel, SELECT);
335                                 ACHANNEL_SET_FLAG(ob, sel, SELECT);
336
337                                 if (ob->adt) {
338                                         ACHANNEL_SET_FLAG(ob, sel, ADT_UI_SELECTED);
339                                 }
340 #endif
341                                 break;
342                         }
343                         case ANIMTYPE_GROUP:
344                         {
345                                 bActionGroup *agrp = (bActionGroup *)ale->data;
346                                 
347                                 ACHANNEL_SET_FLAG(agrp, sel, AGRP_SELECTED);
348                                 agrp->flag &= ~AGRP_ACTIVE;
349                                 break;
350                         }
351                         case ANIMTYPE_FCURVE:
352                         case ANIMTYPE_NLACURVE:
353                         {
354                                 FCurve *fcu = (FCurve *)ale->data;
355                                 
356                                 ACHANNEL_SET_FLAG(fcu, sel, FCURVE_SELECTED);
357                                 fcu->flag &= ~FCURVE_ACTIVE;
358                                 break;
359                         }
360                         case ANIMTYPE_SHAPEKEY:
361                         {
362                                 KeyBlock *kb = (KeyBlock *)ale->data;
363                                 
364                                 ACHANNEL_SET_FLAG(kb, sel, KEYBLOCK_SEL);
365                                 break;
366                         }
367                         case ANIMTYPE_NLATRACK:
368                         {
369                                 NlaTrack *nlt = (NlaTrack *)ale->data;
370                                 
371                                 ACHANNEL_SET_FLAG(nlt, sel, NLATRACK_SELECTED);
372                                 nlt->flag &= ~NLATRACK_ACTIVE;
373                                 break;
374                         }
375                         case ANIMTYPE_FILLACTD: /* Action Expander */
376                         case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
377                         case ANIMTYPE_DSLAM:
378                         case ANIMTYPE_DSCAM:
379                         case ANIMTYPE_DSCACHEFILE:
380                         case ANIMTYPE_DSCUR:
381                         case ANIMTYPE_DSSKEY:
382                         case ANIMTYPE_DSWOR:
383                         case ANIMTYPE_DSPART:
384                         case ANIMTYPE_DSMBALL:
385                         case ANIMTYPE_DSARM:
386                         case ANIMTYPE_DSMESH:
387                         case ANIMTYPE_DSNTREE:
388                         case ANIMTYPE_DSTEX:
389                         case ANIMTYPE_DSLAT:
390                         case ANIMTYPE_DSLINESTYLE:
391                         case ANIMTYPE_DSSPK:
392                         case ANIMTYPE_DSGPENCIL:
393                         case ANIMTYPE_DSMCLIP:
394                         {
395                                 /* need to verify that this data is valid for now */
396                                 if (ale->adt) {
397                                         ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED);
398                                         ale->adt->flag &= ~ADT_UI_ACTIVE;
399                                 }
400                                 break;
401                         }
402                         case ANIMTYPE_GPLAYER:
403                         {
404                                 bGPDlayer *gpl = (bGPDlayer *)ale->data;
405                                 
406                                 ACHANNEL_SET_FLAG(gpl, sel, GP_LAYER_SELECT);
407                                 break;
408                         }
409                         case ANIMTYPE_MASKLAYER:
410                         {
411                                 MaskLayer *masklay = (MaskLayer *)ale->data;
412                                 
413                                 ACHANNEL_SET_FLAG(masklay, sel, MASK_LAYERFLAG_SELECT);
414                                 break;
415                         }
416                 }
417         }
418         
419         /* Cleanup */
420         ANIM_animdata_freelist(&anim_data);
421 }
422
423 /* ---------------------------- Graph Editor ------------------------------------- */
424
425 /* Flush visibility (for Graph Editor) changes up/down hierarchy for changes in the given setting 
426  *      - anim_data: list of the all the anim channels that can be chosen
427  *              -> filtered using ANIMFILTER_CHANNELS only, since if we took VISIBLE too,
428  *                then the channels under closed expanders get ignored...
429  *      - ale_setting: the anim channel (not in the anim_data list directly, though occurring there)
430  *              with the new state of the setting that we want flushed up/down the hierarchy 
431  *      - setting: type of setting to set
432  *      - on: whether the visibility setting has been enabled or disabled 
433  */
434 void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAnimListElem *ale_setting, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode)
435 {
436         bAnimListElem *ale, *match = NULL;
437         int prevLevel = 0, matchLevel = 0;
438         
439         /* sanity check */
440         if (ELEM(NULL, anim_data, anim_data->first))
441                 return;
442
443         if (setting == ACHANNEL_SETTING_ALWAYS_VISIBLE) {
444                 return;
445         }
446
447         /* find the channel that got changed */
448         for (ale = anim_data->first; ale; ale = ale->next) {
449                 /* compare data, and type as main way of identifying the channel */
450                 if ((ale->data == ale_setting->data) && (ale->type == ale_setting->type)) {
451                         /* we also have to check the ID, this is assigned to, since a block may have multiple users */
452                         /* TODO: is the owner-data more revealing? */
453                         if (ale->id == ale_setting->id) {
454                                 match = ale;
455                                 break;
456                         }
457                 }
458         }
459         if (match == NULL) {
460                 printf("ERROR: no channel matching the one changed was found\n");
461                 return;
462         }
463         else {
464                 const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale_setting);
465                 
466                 if (acf == NULL) {
467                         printf("ERROR: no channel info for the changed channel\n");
468                         return;
469                 }
470                 
471                 /* get the level of the channel that was affected
472                  *   - we define the level as simply being the offset for the start of the channel
473                  */
474                 matchLevel = (acf->get_offset) ? acf->get_offset(ac, ale_setting) : 0;
475                 prevLevel = matchLevel;
476         }
477         
478         /* flush up? 
479          *
480          * For Visibility:
481          *      - only flush up if the current state is now enabled (positive 'on' state is default) 
482          *        (otherwise, it's too much work to force the parents to be inactive too)
483          *
484          * For everything else:
485          *      - only flush up if the current state is now disabled (negative 'off' state is default)
486          *        (otherwise, it's too much work to force the parents to be active too)
487          */
488         if ( ((setting == ACHANNEL_SETTING_VISIBLE) && (mode != ACHANNEL_SETFLAG_CLEAR)) ||
489              ((setting != ACHANNEL_SETTING_VISIBLE) && (mode == ACHANNEL_SETFLAG_CLEAR)))
490         {
491                 /* go backwards in the list, until the highest-ranking element (by indention has been covered) */
492                 for (ale = match->prev; ale; ale = ale->prev) {
493                         const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
494                         int level;
495                         
496                         /* if no channel info was found, skip, since this type might not have any useful info */
497                         if (acf == NULL)
498                                 continue;
499                         
500                         /* get the level of the current channel traversed 
501                          *   - we define the level as simply being the offset for the start of the channel
502                          */
503                         level = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
504                         
505                         /* if the level is 'less than' (i.e. more important) the level we're matching
506                          * but also 'less than' the level just tried (i.e. only the 1st group above grouped F-Curves, 
507                          * when toggling visibility of F-Curves, gets flushed, which should happen if we don't let prevLevel
508                          * get updated below once the first 1st group is found)...
509                          */
510                         if (level < prevLevel) {
511                                 /* flush the new status... */
512                                 ANIM_channel_setting_set(ac, ale, setting, mode);
513                                 
514                                 /* store this level as the 'old' level now */
515                                 prevLevel = level;
516                         }
517                         /* if the level is 'greater than' (i.e. less important) than the previous level... */
518                         else if (level > prevLevel) {
519                                 /* if previous level was a base-level (i.e. 0 offset / root of one hierarchy),
520                                  * stop here
521                                  */
522                                 if (prevLevel == 0)
523                                         break;
524                                 /* otherwise, this level weaves into another sibling hierarchy to the previous one just
525                                  * finished, so skip until we get to the parent of this level 
526                                  */
527                                 else
528                                         continue;
529                         }
530                 }
531         }
532         
533         /* flush down (always) */
534         {
535                 /* go forwards in the list, until the lowest-ranking element (by indention has been covered) */
536                 for (ale = match->next; ale; ale = ale->next) {
537                         const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
538                         int level;
539                         
540                         /* if no channel info was found, skip, since this type might not have any useful info */
541                         if (acf == NULL)
542                                 continue;
543                         
544                         /* get the level of the current channel traversed 
545                          *   - we define the level as simply being the offset for the start of the channel
546                          */
547                         level = (acf->get_offset) ? acf->get_offset(ac, ale) : 0;
548                         
549                         /* if the level is 'greater than' (i.e. less important) the channel that was changed, 
550                          * flush the new status...
551                          */
552                         if (level > matchLevel)
553                                 ANIM_channel_setting_set(ac, ale, setting, mode);
554                         /* however, if the level is 'less than or equal to' the channel that was changed,
555                          * (i.e. the current channel is as important if not more important than the changed channel)
556                          * then we should stop, since we've found the last one of the children we should flush
557                          */
558                         else
559                                 break;
560                         
561                         /* store this level as the 'old' level now */
562                         // prevLevel = level; // XXX: prevLevel is unused
563                 }
564         }
565 }
566
567 /* -------------------------- F-Curves ------------------------------------- */
568
569 /* Delete the given F-Curve from its AnimData block */
570 void ANIM_fcurve_delete_from_animdata(bAnimContext *ac, AnimData *adt, FCurve *fcu)
571 {
572         /* - if no AnimData, we've got nowhere to remove the F-Curve from 
573          *      (this doesn't guarantee that the F-Curve is in there, but at least we tried
574          * - if no F-Curve, there is nothing to remove
575          */
576         if (ELEM(NULL, adt, fcu))
577                 return;
578                 
579         /* remove from whatever list it came from
580          *      - Action Group
581          *      - Action
582          *      - Drivers
583          *      - TODO... some others?
584          */
585         if ((ac) && (ac->datatype == ANIMCONT_DRIVERS)) {
586                 /* driver F-Curve */
587                 BLI_remlink(&adt->drivers, fcu);
588         }
589         else if (adt->action) {
590                 bAction *act = adt->action;
591                 
592                 /* remove from group or action, whichever one "owns" the F-Curve */
593                 if (fcu->grp) {
594                         bActionGroup *agrp = fcu->grp;
595                         
596                         /* remove F-Curve from group+action */
597                         action_groups_remove_channel(act, fcu);
598                         
599                         /* if group has no more channels, remove it too, 
600                          * otherwise can have many dangling groups [#33541]
601                          */
602                         if (BLI_listbase_is_empty(&agrp->channels)) {
603                                 BLI_freelinkN(&act->groups, agrp);
604                         }
605                 }
606                 else {
607                         BLI_remlink(&act->curves, fcu);
608                 }
609                 
610                 /* if action has no more F-Curves as a result of this, unlink it from
611                  * AnimData if it did not come from a NLA Strip being tweaked.
612                  *
613                  * This is done so that we don't have dangling Object+Action entries in
614                  * channel list that are empty, and linger around long after the data they
615                  * are for has disappeared (and probably won't come back).
616                  */
617                 if (BLI_listbase_is_empty(&act->curves) && (adt->flag & ADT_NLA_EDIT_ON) == 0) {
618                         id_us_min(&act->id);
619                         adt->action = NULL;
620                 }
621         }
622                 
623         /* free the F-Curve itself */
624         free_fcurve(fcu);
625 }
626
627 /* ************************************************************************** */
628 /* OPERATORS */
629
630 /* ****************** Operator Utilities ********************************** */
631
632 /* poll callback for being in an Animation Editor channels list region */
633 static int animedit_poll_channels_active(bContext *C)
634 {
635         ScrArea *sa = CTX_wm_area(C);
636         
637         /* channels region test */
638         /* TODO: could enhance with actually testing if channels region? */
639         if (ELEM(NULL, sa, CTX_wm_region(C)))
640                 return 0;
641         /* animation editor test */
642         if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
643                 return 0;
644
645         return 1;
646 }
647
648 /* poll callback for Animation Editor channels list region + not in NLA-tweakmode for NLA */
649 static int animedit_poll_channels_nla_tweakmode_off(bContext *C)
650 {
651         ScrArea *sa = CTX_wm_area(C);
652         Scene *scene = CTX_data_scene(C);
653
654         /* channels region test */
655         /* TODO: could enhance with actually testing if channels region? */
656         if (ELEM(NULL, sa, CTX_wm_region(C)))
657                 return 0;
658         /* animation editor test */
659         if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
660                 return 0;
661         
662         /* NLA TweakMode test */
663         if (sa->spacetype == SPACE_NLA) {
664                 if ((scene == NULL) || (scene->flag & SCE_NLA_EDIT_ON))
665                         return 0;
666         }
667                 
668         return 1;
669 }
670
671 /* ****************** Rearrange Channels Operator ******************* */
672
673 /* constants for channel rearranging */
674 /* WARNING: don't change existing ones without modifying rearrange func accordingly */
675 typedef enum eRearrangeAnimChan_Mode {
676         REARRANGE_ANIMCHAN_TOP = -2,
677         REARRANGE_ANIMCHAN_UP = -1,
678         REARRANGE_ANIMCHAN_DOWN = 1,
679         REARRANGE_ANIMCHAN_BOTTOM = 2
680 } eRearrangeAnimChan_Mode;
681
682 /* defines for rearranging channels */
683 static EnumPropertyItem prop_animchannel_rearrange_types[] = {
684         {REARRANGE_ANIMCHAN_TOP, "TOP", 0, "To Top", ""},
685         {REARRANGE_ANIMCHAN_UP, "UP", 0, "Up", ""},
686         {REARRANGE_ANIMCHAN_DOWN, "DOWN", 0, "Down", ""},
687         {REARRANGE_ANIMCHAN_BOTTOM, "BOTTOM", 0, "To Bottom", ""},
688         {0, NULL, 0, NULL, NULL}
689 };
690
691 /* Reordering "Islands" Defines ----------------------------------- */
692
693 /* Island definition - just a listbase container */
694 typedef struct tReorderChannelIsland {
695         struct tReorderChannelIsland *next, *prev;
696         
697         ListBase channels;  /* channels within this region with the same state */
698         int flag;           /* eReorderIslandFlag */
699 } tReorderChannelIsland;
700
701 /* flags for channel reordering islands */
702 typedef enum eReorderIslandFlag {
703         REORDER_ISLAND_SELECTED         = (1 << 0),   /* island is selected */
704         REORDER_ISLAND_UNTOUCHABLE      = (1 << 1),   /* island should be ignored */
705         REORDER_ISLAND_MOVED            = (1 << 2),   /* island has already been moved */
706         REORDER_ISLAND_HIDDEN           = (1 << 3),   /* island is not visible */
707 } eReorderIslandFlag;
708
709
710 /* Rearrange Methods --------------------------------------------- */
711
712 static bool rearrange_island_ok(tReorderChannelIsland *island)
713 {
714         /* island must not be untouchable */
715         if (island->flag & REORDER_ISLAND_UNTOUCHABLE)
716                 return 0;
717         
718         /* island should be selected to be moved */
719         return (island->flag & REORDER_ISLAND_SELECTED) && !(island->flag & REORDER_ISLAND_MOVED);
720 }
721
722 /* ............................. */
723
724 static bool rearrange_island_top(ListBase *list, tReorderChannelIsland *island)
725 {
726         if (rearrange_island_ok(island)) {
727                 /* remove from current position */
728                 BLI_remlink(list, island);
729                 
730                 /* make it first element */
731                 BLI_insertlinkbefore(list, list->first, island);
732                 
733                 return 1;
734         }
735         
736         return 0;
737 }
738
739 static bool rearrange_island_up(ListBase *list, tReorderChannelIsland *island)
740 {
741         if (rearrange_island_ok(island)) {
742                 /* moving up = moving before the previous island, otherwise we're in the same place */
743                 tReorderChannelIsland *prev = island->prev;
744
745                 /* Skip hidden islands! */
746                 while (prev && prev->flag & REORDER_ISLAND_HIDDEN) {
747                         prev = prev->prev;
748                 }
749
750                 if (prev) {
751                         /* remove from current position */
752                         BLI_remlink(list, island);
753                         
754                         /* push it up */
755                         BLI_insertlinkbefore(list, prev, island);
756                         
757                         return 1;
758                 }
759         }
760         
761         return 0;
762 }
763
764 static bool rearrange_island_down(ListBase *list, tReorderChannelIsland *island)
765 {
766         if (rearrange_island_ok(island)) {
767                 /* moving down = moving after the next island, otherwise we're in the same place */
768                 tReorderChannelIsland *next = island->next;
769
770                 /* Skip hidden islands! */
771                 while (next && next->flag & REORDER_ISLAND_HIDDEN) {
772                         next = next->next;
773                 }
774
775                 if (next) {
776                         /* can only move past if next is not untouchable (i.e. nothing can go after it) */
777                         if ((next->flag & REORDER_ISLAND_UNTOUCHABLE) == 0) {
778                                 /* remove from current position */
779                                 BLI_remlink(list, island);
780                                 
781                                 /* push it down */
782                                 BLI_insertlinkafter(list, next, island);
783                                 
784                                 return true;
785                         }
786                 }
787                 /* else: no next channel, so we're at the bottom already, so can't move */
788         }
789         
790         return false;
791 }
792
793 static bool rearrange_island_bottom(ListBase *list, tReorderChannelIsland *island)
794 {
795         if (rearrange_island_ok(island)) {
796                 tReorderChannelIsland *last = list->last;
797                 
798                 /* remove island from current position */
799                 BLI_remlink(list, island);
800                 
801                 /* add before or after the last channel? */
802                 if ((last->flag & REORDER_ISLAND_UNTOUCHABLE) == 0) {
803                         /* can add after it */
804                         BLI_addtail(list, island);
805                 }
806                 else {
807                         /* can at most go just before it, since last cannot be moved */
808                         BLI_insertlinkbefore(list, last, island);
809                         
810                 }
811                 
812                 return true;
813         }
814         
815         return false;
816 }
817
818 /* ............................. */
819
820 /**
821  * typedef for channel rearranging function
822  *
823  * \param list List of tReorderChannelIsland's that channels belong to
824  * \param island Island to be moved
825  * \return Whether operation was a success
826  */
827 typedef bool (*AnimChanRearrangeFp)(ListBase *list, tReorderChannelIsland *island);
828
829 /* get rearranging function, given 'rearrange' mode */
830 static AnimChanRearrangeFp rearrange_get_mode_func(eRearrangeAnimChan_Mode mode)
831 {
832         switch (mode) {
833                 case REARRANGE_ANIMCHAN_TOP:
834                         return rearrange_island_top;
835                 case REARRANGE_ANIMCHAN_UP:
836                         return rearrange_island_up;
837                 case REARRANGE_ANIMCHAN_DOWN:
838                         return rearrange_island_down;
839                 case REARRANGE_ANIMCHAN_BOTTOM:
840                         return rearrange_island_bottom;
841                 default:
842                         return NULL;
843         }
844 }
845
846 /* Rearrange Islands Generics ------------------------------------- */
847
848 /* add channel into list of islands */
849 static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *srcList,
850                                                  Link *channel, eAnim_ChannelType type,
851                                                  const bool is_hidden)
852 {
853         tReorderChannelIsland *island = islands->last;  /* always try to add to last island if possible */
854         bool is_sel = false, is_untouchable = false;
855         
856         /* get flags - selected and untouchable from the channel */
857         switch (type) {
858                 case ANIMTYPE_GROUP:
859                 {
860                         bActionGroup *agrp = (bActionGroup *)channel;
861                         
862                         is_sel = SEL_AGRP(agrp);
863                         is_untouchable = (agrp->flag & AGRP_TEMP) != 0;
864                         break;
865                 }
866                 case ANIMTYPE_FCURVE:
867                 case ANIMTYPE_NLACURVE:
868                 {
869                         FCurve *fcu = (FCurve *)channel;
870                         
871                         is_sel = SEL_FCU(fcu);
872                         break;
873                 }
874                 case ANIMTYPE_NLATRACK:
875                 {
876                         NlaTrack *nlt = (NlaTrack *)channel;
877                         
878                         is_sel = SEL_NLT(nlt);
879                         break;
880                 }
881                 case ANIMTYPE_GPLAYER:
882                 {
883                         bGPDlayer *gpl = (bGPDlayer *)channel;
884                         
885                         is_sel = SEL_GPL(gpl);
886                         break;
887                 }
888                 default:
889                         printf("rearrange_animchannel_add_to_islands(): don't know how to handle channels of type %u\n", type);
890                         return;
891         }
892         
893         /* do we need to add to a new island? */
894         if (/* 1) no islands yet */
895             (island == NULL) ||
896             /* 2) unselected islands have single channels only - to allow up/down movement */
897             ((island->flag & REORDER_ISLAND_SELECTED) == 0) ||
898             /* 3) if channel is unselected, stop existing island (it was either wrong sel status, or full already) */
899             (is_sel == 0) ||
900             /* 4) hidden status changes */
901             ((island->flag & REORDER_ISLAND_HIDDEN) != is_hidden)
902             )
903         {
904                 /* create a new island now */
905                 island = MEM_callocN(sizeof(tReorderChannelIsland), "tReorderChannelIsland");
906                 BLI_addtail(islands, island);
907                 
908                 if (is_sel)
909                         island->flag |= REORDER_ISLAND_SELECTED;
910                 if (is_untouchable)
911                         island->flag |= REORDER_ISLAND_UNTOUCHABLE;
912                 if (is_hidden)
913                         island->flag |= REORDER_ISLAND_HIDDEN;
914         }
915
916         /* add channel to island - need to remove it from its existing list first though */
917         BLI_remlink(srcList, channel);
918         BLI_addtail(&island->channels, channel);
919 }
920
921 /* flatten islands out into a single list again */
922 static void rearrange_animchannel_flatten_islands(ListBase *islands, ListBase *srcList)
923 {
924         tReorderChannelIsland *island, *isn = NULL;
925         
926         /* make sure srcList is empty now */
927         BLI_assert(BLI_listbase_is_empty(srcList));
928         
929         /* go through merging islands */
930         for (island = islands->first; island; island = isn) {
931                 isn = island->next;
932                 
933                 /* merge island channels back to main list, then delete the island */
934                 BLI_movelisttolist(srcList, &island->channels);
935                 BLI_freelinkN(islands, island);
936         }
937 }
938
939 /* ............................. */
940
941 /* get a list of all bAnimListElem's of a certain type which are currently visible */
942 static void rearrange_animchannels_filter_visible(ListBase *anim_data_visible, bAnimContext *ac, eAnim_ChannelType type)
943 {
944         ListBase anim_data = {NULL, NULL};
945         bAnimListElem *ale, *ale_next;
946         int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
947         
948         /* get all visible channels */
949         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
950         
951         /* now, only keep the ones that are of the types we are interested in */
952         for (ale = anim_data.first; ale; ale = ale_next) {
953                 ale_next = ale->next;
954                 
955                 if (ale->type != type) {
956                         BLI_freelinkN(&anim_data, ale);
957                 }
958         }
959         
960         /* return cleaned up list */
961         *anim_data_visible = anim_data;
962 }
963
964 /* performing rearranging of channels using islands */
965 static bool rearrange_animchannel_islands(ListBase *list, AnimChanRearrangeFp rearrange_func,
966                                           eRearrangeAnimChan_Mode mode, eAnim_ChannelType type,
967                                           ListBase *anim_data_visible)
968 {
969         ListBase islands = {NULL, NULL};
970         Link *channel, *chanNext = NULL;
971         bool done = false;
972         
973         /* don't waste effort on an empty list */
974         if (BLI_listbase_is_empty(list))
975                 return 0;
976         
977         /* group channels into islands */
978         for (channel = list->first; channel; channel = chanNext) {
979                 /* find out whether this channel is present in anim_data_visible or not! */
980                 const bool is_hidden = (BLI_findptr(anim_data_visible, channel, offsetof(bAnimListElem, data)) == NULL);
981                 chanNext = channel->next;
982                 rearrange_animchannel_add_to_islands(&islands, list, channel, type, is_hidden);
983         }
984         
985         /* perform moving of selected islands now, but only if there is more than one of 'em so that something will happen 
986          *      - scanning of the list is performed in the opposite direction to the direction we're moving things, so that we 
987          *        shouldn't need to encounter items we've moved already
988          */
989         if (islands.first != islands.last) {
990                 tReorderChannelIsland *first = (mode > 0) ? islands.last : islands.first;
991                 tReorderChannelIsland *island, *isn = NULL;
992                 
993                 for (island = first; island; island = isn) {
994                         isn = (mode > 0) ? island->prev : island->next;
995                         
996                         /* perform rearranging */
997                         if (rearrange_func(&islands, island)) {
998                                 island->flag |= REORDER_ISLAND_MOVED;
999                                 done = true;
1000                         }
1001                 }
1002         }
1003         
1004         /* ungroup islands */
1005         rearrange_animchannel_flatten_islands(&islands, list);
1006         
1007         /* did we do anything? */
1008         return done;
1009 }
1010
1011 /* NLA Specific Stuff ----------------------------------------------------- */
1012
1013 /* Change the order NLA Tracks within NLA Stack
1014  * ! NLA tracks are displayed in opposite order, so directions need care
1015  *      mode: REARRANGE_ANIMCHAN_*  
1016  */
1017 static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
1018 {
1019         AnimChanRearrangeFp rearrange_func;
1020         ListBase anim_data_visible = {NULL, NULL};
1021         
1022         /* hack: invert mode so that functions will work in right order */
1023         mode *= -1;
1024         
1025         /* get rearranging function */
1026         rearrange_func = rearrange_get_mode_func(mode);
1027         if (rearrange_func == NULL)
1028                 return;
1029         
1030         /* Filter visible data. */
1031         rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLATRACK);
1032         
1033         /* perform rearranging on tracks list */
1034         rearrange_animchannel_islands(&adt->nla_tracks, rearrange_func, mode, ANIMTYPE_NLATRACK, &anim_data_visible);
1035         
1036         /* free temp data */
1037         BLI_freelistN(&anim_data_visible);
1038 }
1039
1040 /* Drivers Specific Stuff ------------------------------------------------- */
1041
1042 /* Change the order drivers within AnimData block
1043  *      mode: REARRANGE_ANIMCHAN_*  
1044  */
1045 static void rearrange_driver_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
1046 {
1047         /* get rearranging function */
1048         AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
1049         ListBase anim_data_visible = {NULL, NULL};
1050         
1051         if (rearrange_func == NULL)
1052                 return;
1053         
1054         /* only consider drivers if they're accessible */
1055         if (EXPANDED_DRVD(adt) == 0)
1056                 return;
1057         
1058         /* Filter visible data. */
1059         rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_FCURVE);
1060         
1061         /* perform rearranging on drivers list (drivers are really just F-Curves) */
1062         rearrange_animchannel_islands(&adt->drivers, rearrange_func, mode, ANIMTYPE_FCURVE, &anim_data_visible);
1063         
1064         /* free temp data */
1065         BLI_freelistN(&anim_data_visible);
1066 }
1067
1068 /* Action Specific Stuff ------------------------------------------------- */
1069
1070 /* make sure all action-channels belong to a group (and clear action's list) */
1071 static void split_groups_action_temp(bAction *act, bActionGroup *tgrp)
1072 {
1073         bActionGroup *agrp;
1074         FCurve *fcu;
1075         
1076         if (act == NULL)
1077                 return;
1078         
1079         /* Separate F-Curves into lists per group */
1080         for (agrp = act->groups.first; agrp; agrp = agrp->next) {
1081                 if (agrp->channels.first) {
1082                         fcu = agrp->channels.last;
1083                         act->curves.first = fcu->next;
1084                         
1085                         fcu = agrp->channels.first;
1086                         fcu->prev = NULL;
1087                         
1088                         fcu = agrp->channels.last;
1089                         fcu->next = NULL;
1090                 }
1091         }
1092         
1093         /* Initialize memory for temp-group */
1094         memset(tgrp, 0, sizeof(bActionGroup));
1095         tgrp->flag |= (AGRP_EXPANDED | AGRP_TEMP);
1096         BLI_strncpy(tgrp->name, "#TempGroup", sizeof(tgrp->name));
1097         
1098         /* Move any action-channels not already moved, to the temp group */
1099         if (act->curves.first) {
1100                 /* start of list */
1101                 fcu = act->curves.first;
1102                 fcu->prev = NULL;
1103                 tgrp->channels.first = fcu;
1104                 act->curves.first = NULL;
1105                 
1106                 /* end of list */
1107                 fcu = act->curves.last;
1108                 fcu->next = NULL;
1109                 tgrp->channels.last = fcu;
1110                 act->curves.last = NULL;
1111                 
1112                 /* ensure that all of these get their group set to this temp group 
1113                  * (so that visibility filtering works)
1114                  */
1115                 for (fcu = tgrp->channels.first; fcu; fcu = fcu->next) {
1116                         fcu->grp = tgrp;
1117                 }
1118         }
1119         
1120         /* Add temp-group to list */
1121         BLI_addtail(&act->groups, tgrp);
1122 }
1123
1124 /* link lists of channels that groups have */
1125 static void join_groups_action_temp(bAction *act)
1126 {
1127         bActionGroup *agrp;
1128         
1129         for (agrp = act->groups.first; agrp; agrp = agrp->next) {
1130                 ListBase tempGroup;
1131                 
1132                 /* add list of channels to action's channels */
1133                 tempGroup = agrp->channels;
1134                 BLI_movelisttolist(&act->curves, &agrp->channels);
1135                 agrp->channels = tempGroup;
1136                 
1137                 /* clear moved flag */
1138                 agrp->flag &= ~AGRP_MOVED;
1139                 
1140                 /* if group was temporary one:
1141                  * - unassign all FCurves which were temporarily added to it
1142                  * - remove from list (but don't free as it's on the stack!)
1143                  */
1144                 if (agrp->flag & AGRP_TEMP) {
1145                         FCurve *fcu;
1146                         
1147                         for (fcu = agrp->channels.first; fcu; fcu = fcu->next) {
1148                                 fcu->grp = NULL;
1149                         }
1150                         
1151                         BLI_remlink(&act->groups, agrp);
1152                         break;
1153                 }
1154         }
1155 }
1156
1157 /* Change the order of anim-channels within action 
1158  *      mode: REARRANGE_ANIMCHAN_*  
1159  */
1160 static void rearrange_action_channels(bAnimContext *ac, bAction *act, eRearrangeAnimChan_Mode mode)
1161 {
1162         bActionGroup tgrp;
1163         ListBase anim_data_visible = {NULL, NULL};
1164         bool do_channels;
1165         
1166         /* get rearranging function */
1167         AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
1168         
1169         if (rearrange_func == NULL)
1170                 return;
1171         
1172         /* make sure we're only operating with groups (vs a mixture of groups+curves) */
1173         split_groups_action_temp(act, &tgrp);
1174         
1175         /* Filter visible data. */
1176         rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_GROUP);
1177         
1178         /* rearrange groups first 
1179          *      - the group's channels will only get considered if nothing happened when rearranging the groups
1180          *        i.e. the rearrange function returned 0
1181          */
1182         do_channels = (rearrange_animchannel_islands(&act->groups, rearrange_func, mode, ANIMTYPE_GROUP,
1183                                                      &anim_data_visible) == 0);
1184         
1185         /* free temp data */
1186         BLI_freelistN(&anim_data_visible);
1187         
1188         if (do_channels) {
1189                 bActionGroup *agrp;
1190                 
1191                 /* Filter visible data. */
1192                 rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_FCURVE);
1193                 
1194                 for (agrp = act->groups.first; agrp; agrp = agrp->next) {
1195                         /* only consider F-Curves if they're visible (group expanded) */
1196                         if (EXPANDED_AGRP(ac, agrp)) {
1197                                 rearrange_animchannel_islands(&agrp->channels, rearrange_func, mode, ANIMTYPE_FCURVE,
1198                                                               &anim_data_visible);
1199                         }
1200                 }
1201                 
1202                 /* free temp data */
1203                 BLI_freelistN(&anim_data_visible);
1204         }
1205         
1206         /* assemble lists into one list (and clear moved tags) */
1207         join_groups_action_temp(act);
1208 }
1209
1210 /* ------------------- */
1211
1212 static void rearrange_nla_control_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
1213 {
1214         ListBase anim_data_visible = {NULL, NULL};
1215         
1216         NlaTrack *nlt;
1217         NlaStrip *strip;
1218         
1219         /* get rearranging function */
1220         AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
1221         
1222         if (rearrange_func == NULL)
1223                 return;
1224                 
1225         /* skip if these curves aren't being shown */
1226         if (adt->flag & ADT_NLA_SKEYS_COLLAPSED)
1227                 return;
1228         
1229         /* Filter visible data. */
1230         rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLACURVE);
1231         
1232         /* we cannot rearrange between strips, but within each strip, we can rearrange those curves */
1233         for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1234                 for (strip = nlt->strips.first; strip; strip = strip->next) {
1235                         rearrange_animchannel_islands(&strip->fcurves, rearrange_func, mode, ANIMTYPE_NLACURVE,
1236                                                           &anim_data_visible);
1237                 }
1238         }
1239         
1240         /* free temp data */
1241         BLI_freelistN(&anim_data_visible);
1242 }
1243
1244 /* ------------------- */
1245
1246 static void rearrange_gpencil_channels(bAnimContext *ac, eRearrangeAnimChan_Mode mode)
1247 {
1248         ListBase anim_data = {NULL, NULL};
1249         bAnimListElem *ale;
1250         int filter;
1251         
1252         /* get rearranging function */
1253         AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
1254         
1255         if (rearrange_func == NULL)
1256                 return;
1257         
1258         /* get Grease Pencil datablocks */
1259         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA);
1260         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1261         
1262         for (ale = anim_data.first; ale; ale = ale->next) {
1263                 ListBase anim_data_visible = {NULL, NULL};
1264                 bGPdata *gpd = ale->data;
1265                 
1266                 /* only consider layers if this datablock is open */
1267                 BLI_assert(ale->type == ANIMTYPE_GPDATABLOCK);
1268                 if ((gpd->flag & GP_DATA_EXPAND) == 0)
1269                         continue;
1270                 
1271                 /* Filter visible data. */
1272                 rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_GPLAYER);
1273                 
1274                 /* rearrange datablock's layers */
1275                 rearrange_animchannel_islands(&gpd->layers, rearrange_func, mode, ANIMTYPE_GPLAYER, &anim_data_visible);
1276                 
1277                 /* free visible layers data */
1278                 BLI_freelistN(&anim_data_visible);
1279         }
1280         
1281         /* free GPD channel data */
1282         ANIM_animdata_freelist(&anim_data);
1283 }
1284
1285 /* ------------------- */
1286
1287 static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
1288 {
1289         bAnimContext ac;
1290         eRearrangeAnimChan_Mode mode;
1291         
1292         /* get editor data */
1293         if (ANIM_animdata_get_context(C, &ac) == 0)
1294                 return OPERATOR_CANCELLED;
1295                 
1296         /* get mode */
1297         mode = RNA_enum_get(op->ptr, "direction");
1298         
1299         /* method to move channels depends on the editor */
1300         if (ac.datatype == ANIMCONT_GPENCIL) {
1301                 /* Grease Pencil channels */
1302                 rearrange_gpencil_channels(&ac, mode);
1303         }
1304         else if (ac.datatype == ANIMCONT_MASK) {
1305                 /* Grease Pencil channels */
1306                 printf("Mask does not supported for moving yet\n");
1307         }
1308         else if (ac.datatype == ANIMCONT_ACTION) {
1309                 /* Directly rearrange action's channels */
1310                 rearrange_action_channels(&ac, ac.data, mode);
1311         }
1312         else {
1313                 ListBase anim_data = {NULL, NULL};
1314                 bAnimListElem *ale;
1315                 int filter;
1316                 
1317                 /* get animdata blocks */
1318                 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA);
1319                 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1320                 
1321                 for (ale = anim_data.first; ale; ale = ale->next) {
1322                         AnimData *adt = ale->data;
1323                         
1324                         switch (ac.datatype) {
1325                                 case ANIMCONT_NLA: /* NLA-tracks only */
1326                                         rearrange_nla_channels(&ac, adt, mode);
1327                                         break;
1328                                 
1329                                 case ANIMCONT_DRIVERS: /* Drivers list only */
1330                                         rearrange_driver_channels(&ac, adt, mode);
1331                                         break;
1332                                 
1333                                 case ANIMCONT_ACTION: /* Single Action only... */
1334                                 case ANIMCONT_SHAPEKEY: // DOUBLE CHECK ME...
1335                                 {
1336                                         if (adt->action)
1337                                                 rearrange_action_channels(&ac, adt->action, mode);
1338                                         else if (G.debug & G_DEBUG)
1339                                                 printf("Animdata has no action\n");
1340                                         break;
1341                                 }
1342                                 
1343                                 default: /* DopeSheet/Graph Editor - Some Actions + NLA Control Curves */
1344                                 {
1345                                         /* NLA Control Curves */
1346                                         if (adt->nla_tracks.first)
1347                                                 rearrange_nla_control_channels(&ac, adt, mode);
1348                                         
1349                                         /* Action */
1350                                         if (adt->action)
1351                                                 rearrange_action_channels(&ac, adt->action, mode);
1352                                         else if (G.debug & G_DEBUG)
1353                                                 printf("Animdata has no action\n");
1354                                         break;
1355                                 }
1356                         }
1357                 }
1358                 
1359                 /* free temp data */
1360                 ANIM_animdata_freelist(&anim_data);
1361         }
1362         
1363         /* send notifier that things have changed */
1364         WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
1365         
1366         return OPERATOR_FINISHED;
1367 }
1368
1369 static void ANIM_OT_channels_move(wmOperatorType *ot)
1370 {
1371         /* identifiers */
1372         ot->name = "Move Channels";
1373         ot->idname = "ANIM_OT_channels_move";
1374         ot->description = "Rearrange selected animation channels";
1375         
1376         /* api callbacks */
1377         ot->exec = animchannels_rearrange_exec;
1378         ot->poll = animedit_poll_channels_nla_tweakmode_off;
1379         
1380         /* flags */
1381         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1382         
1383         /* props */
1384         ot->prop = RNA_def_enum(ot->srna, "direction", prop_animchannel_rearrange_types, REARRANGE_ANIMCHAN_DOWN, "Direction", "");
1385 }
1386
1387 /* ******************** Group Channel Operator ************************ */
1388
1389 static int animchannels_grouping_poll(bContext *C)
1390 {
1391         ScrArea *sa = CTX_wm_area(C);
1392         SpaceLink *sl;
1393
1394         /* channels region test */
1395         /* TODO: could enhance with actually testing if channels region? */
1396         if (ELEM(NULL, sa, CTX_wm_region(C)))
1397                 return 0;
1398                 
1399         /* animation editor test - must be suitable modes only */
1400         sl = CTX_wm_space_data(C);
1401         
1402         switch (sa->spacetype) {
1403                 /* supported... */
1404                 case SPACE_ACTION:
1405                 {
1406                         SpaceAction *saction = (SpaceAction *)sl;
1407                         
1408                         /* dopesheet and action only - all others are for other datatypes or have no groups */
1409                         if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_DOPESHEET) == 0)
1410                                 return 0;
1411
1412                         break;
1413                 }
1414                 case SPACE_IPO:
1415                 {
1416                         SpaceIpo *sipo = (SpaceIpo *)sl;
1417                         
1418                         /* drivers can't have groups... */
1419                         if (sipo->mode != SIPO_MODE_ANIMATION)
1420                                 return 0;
1421
1422                         break;
1423                 }
1424                 /* unsupported... */
1425                 default:
1426                         return 0;
1427         }
1428         
1429         return 1;
1430 }
1431
1432 /* ----------------------------------------------------------- */
1433
1434 static void animchannels_group_channels(bAnimContext *ac, bAnimListElem *adt_ref, const char name[])
1435 {       
1436         AnimData *adt = adt_ref->adt;
1437         bAction *act = adt->action;
1438         
1439         if (act) {
1440                 ListBase anim_data = {NULL, NULL};
1441                 int filter;
1442                 
1443                 /* find selected F-Curves to re-group */
1444                 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL);
1445                 ANIM_animdata_filter(ac, &anim_data, filter, adt_ref, ANIMCONT_CHANNEL);
1446                 
1447                 if (anim_data.first) {
1448                         bActionGroup *agrp;
1449                         bAnimListElem *ale;
1450                         
1451                         /* create new group, which should now be part of the action */
1452                         agrp = action_groups_add_new(act, name);
1453                         BLI_assert(agrp != NULL);
1454                         
1455                         /* transfer selected F-Curves across to new group  */
1456                         for (ale = anim_data.first; ale; ale = ale->next) {
1457                                 FCurve *fcu = (FCurve *)ale->data;
1458                                 bActionGroup *grp = fcu->grp;
1459                                 
1460                                 /* remove F-Curve from group, then group too if it is now empty */
1461                                 action_groups_remove_channel(act, fcu);
1462                                 
1463                                 if ((grp) && BLI_listbase_is_empty(&grp->channels)) {
1464                                         BLI_freelinkN(&act->groups, grp);
1465                                 }
1466                                 
1467                                 /* add F-Curve to group */
1468                                 action_groups_add_channel(act, agrp, fcu);
1469                         }
1470                 }
1471                 
1472                 /* cleanup */
1473                 ANIM_animdata_freelist(&anim_data);
1474         }
1475 }
1476
1477 static int animchannels_group_exec(bContext *C, wmOperator *op)
1478 {
1479         bAnimContext ac;
1480         char name[MAX_NAME];
1481         
1482         /* get editor data */
1483         if (ANIM_animdata_get_context(C, &ac) == 0)
1484                 return OPERATOR_CANCELLED;
1485         
1486         /* get name for new group */
1487         RNA_string_get(op->ptr, "name", name);
1488         
1489         /* XXX: name for group should never be empty... */
1490         if (name[0]) {
1491                 ListBase anim_data = {NULL, NULL};
1492                 bAnimListElem *ale;
1493                 int filter;
1494                 
1495                 /* handle each animdata block separately, so that the regrouping doesn't flow into blocks  */
1496                 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_NODUPLIS);
1497                 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1498                 
1499                 for (ale = anim_data.first; ale; ale = ale->next) {
1500                         animchannels_group_channels(&ac, ale, name);
1501                 }
1502                 
1503                 /* free temp data */
1504                 ANIM_animdata_freelist(&anim_data);
1505                 
1506                 /* updatss */
1507                 WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
1508         }
1509         
1510         return OPERATOR_FINISHED;
1511 }
1512
1513 static void ANIM_OT_channels_group(wmOperatorType *ot)
1514 {
1515         /* identifiers */
1516         ot->name = "Group Channels";
1517         ot->idname = "ANIM_OT_channels_group";
1518         ot->description = "Add selected F-Curves to a new group";
1519         
1520         /* callbacks */
1521         ot->invoke = WM_operator_props_popup;
1522         ot->exec = animchannels_group_exec;
1523         ot->poll = animchannels_grouping_poll;
1524         
1525         /* flags */
1526         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1527         
1528         /* props */
1529         ot->prop = RNA_def_string(ot->srna, "name", "New Group", 
1530                                   sizeof(((bActionGroup *)NULL)->name), 
1531                                   "Name", "Name of newly created group");
1532         /* RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); */ /* XXX: still not too sure about this - keeping same text is confusing... */
1533 }
1534
1535 /* ----------------------------------------------------------- */
1536
1537 static int animchannels_ungroup_exec(bContext *C, wmOperator *UNUSED(op))
1538 {
1539         bAnimContext ac;
1540         
1541         ListBase anim_data = {NULL, NULL};
1542         bAnimListElem *ale;
1543         int filter;
1544         
1545         /* get editor data */
1546         if (ANIM_animdata_get_context(C, &ac) == 0)
1547                 return OPERATOR_CANCELLED;
1548                 
1549         /* just selected F-Curves... */
1550         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
1551         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1552         
1553         for (ale = anim_data.first; ale; ale = ale->next) {
1554                 /* find action for this F-Curve... */
1555                 if (ale->adt && ale->adt->action) {
1556                         FCurve  *fcu = (FCurve *)ale->data;
1557                         bAction *act = ale->adt->action;
1558                         
1559                         /* only proceed to remove if F-Curve is in a group... */
1560                         if (fcu->grp) { 
1561                                 bActionGroup *agrp = fcu->grp;
1562                                 
1563                                 /* remove F-Curve from group and add at tail (ungrouped) */
1564                                 action_groups_remove_channel(act, fcu);
1565                                 BLI_addtail(&act->curves, fcu);
1566                                 
1567                                 /* delete group if it is now empty */
1568                                 if (BLI_listbase_is_empty(&agrp->channels)) {
1569                                         BLI_freelinkN(&act->groups, agrp);
1570                                 }
1571                         }
1572                 }
1573         }
1574         
1575         /* cleanup */
1576         ANIM_animdata_freelist(&anim_data);
1577         
1578         /* updates */
1579         WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
1580         
1581         return OPERATOR_FINISHED;
1582 }
1583
1584 static void ANIM_OT_channels_ungroup(wmOperatorType *ot)
1585 {
1586         /* identifiers */
1587         ot->name = "Ungroup Channels";
1588         ot->idname = "ANIM_OT_channels_ungroup";
1589         ot->description = "Remove selected F-Curves from their current groups";
1590         
1591         /* callbacks */
1592         ot->exec = animchannels_ungroup_exec;
1593         ot->poll = animchannels_grouping_poll;
1594         
1595         /* flags */
1596         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1597 }
1598
1599 /* ******************** Delete Channel Operator *********************** */
1600
1601 static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
1602 {
1603         bAnimContext ac;
1604         ListBase anim_data = {NULL, NULL};
1605         bAnimListElem *ale;
1606         int filter;
1607         
1608         /* get editor data */
1609         if (ANIM_animdata_get_context(C, &ac) == 0)
1610                 return OPERATOR_CANCELLED;
1611         
1612         /* cannot delete in shapekey */
1613         if (ac.datatype == ANIMCONT_SHAPEKEY) 
1614                 return OPERATOR_CANCELLED;
1615                 
1616                 
1617         /* do groups only first (unless in Drivers mode, where there are none) */
1618         if (ac.datatype != ANIMCONT_DRIVERS) {
1619                 /* filter data */
1620                 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
1621                 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1622                 
1623                 /* delete selected groups and their associated channels */
1624                 for (ale = anim_data.first; ale; ale = ale->next) {
1625                         /* only groups - don't check other types yet, since they may no-longer exist */
1626                         if (ale->type == ANIMTYPE_GROUP) {
1627                                 bActionGroup *agrp = (bActionGroup *)ale->data;
1628                                 AnimData *adt = ale->adt;
1629                                 FCurve *fcu, *fcn;
1630                                 
1631                                 /* skip this group if no AnimData available, as we can't safely remove the F-Curves */
1632                                 if (adt == NULL)
1633                                         continue;
1634                                 
1635                                 /* delete all of the Group's F-Curves, but no others */
1636                                 for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcn) {
1637                                         fcn = fcu->next;
1638                                         
1639                                         /* remove from group and action, then free */
1640                                         action_groups_remove_channel(adt->action, fcu);
1641                                         free_fcurve(fcu);
1642                                 }
1643                                 
1644                                 /* free the group itself */
1645                                 if (adt->action)
1646                                         BLI_freelinkN(&adt->action->groups, agrp);
1647                                 else
1648                                         MEM_freeN(agrp);
1649                         }
1650                 }
1651                 
1652                 /* cleanup */
1653                 ANIM_animdata_freelist(&anim_data);
1654         }
1655         
1656         /* filter data */
1657         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
1658         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
1659         
1660         /* delete selected data channels */
1661         for (ale = anim_data.first; ale; ale = ale->next) {
1662                 switch (ale->type) {
1663                         case ANIMTYPE_FCURVE: 
1664                         {
1665                                 /* F-Curves if we can identify its parent */
1666                                 AnimData *adt = ale->adt;
1667                                 FCurve *fcu = (FCurve *)ale->data;
1668                                 
1669                                 /* try to free F-Curve */
1670                                 ANIM_fcurve_delete_from_animdata(&ac, adt, fcu);
1671                                 break;
1672                         }
1673                         case ANIMTYPE_NLACURVE:
1674                         {
1675                                 /* NLA Control Curve - Deleting it should disable the corresponding setting... */
1676                                 NlaStrip *strip = (NlaStrip *)ale->owner;
1677                                 FCurve *fcu = (FCurve *)ale->data;
1678                                 
1679                                 if (STREQ(fcu->rna_path, "strip_time")) {
1680                                         strip->flag &= ~NLASTRIP_FLAG_USR_TIME;
1681                                 }
1682                                 else if (STREQ(fcu->rna_path, "influence")) {
1683                                         strip->flag &= ~NLASTRIP_FLAG_USR_INFLUENCE;
1684                                 }
1685                                 else {
1686                                         printf("ERROR: Trying to delete NLA Control Curve for unknown property '%s'\n", fcu->rna_path);
1687                                 }
1688                                 
1689                                 /* unlink and free the F-Curve */
1690                                 BLI_remlink(&strip->fcurves, fcu);
1691                                 free_fcurve(fcu);
1692                                 break;
1693                         }
1694                         case ANIMTYPE_GPLAYER:
1695                         {
1696                                 /* Grease Pencil layer */
1697                                 bGPdata *gpd = (bGPdata *)ale->id;
1698                                 bGPDlayer *gpl = (bGPDlayer *)ale->data;
1699                                 
1700                                 /* try to delete the layer's data and the layer itself */
1701                                 BKE_gpencil_free_frames(gpl);
1702                                 BLI_freelinkN(&gpd->layers, gpl);
1703                                 break;
1704                         }
1705                         case ANIMTYPE_MASKLAYER:
1706                         {
1707                                 /* Mask layer */
1708                                 Mask *mask = (Mask *)ale->id;
1709                                 MaskLayer *masklay = (MaskLayer *)ale->data;
1710                                 
1711                                 /* try to delete the layer's data and the layer itself */
1712                                 BKE_mask_layer_remove(mask, masklay);
1713                                 break;
1714                         }
1715                 }
1716         }
1717         
1718         /* cleanup */
1719         ANIM_animdata_freelist(&anim_data);
1720         
1721         /* send notifier that things have changed */
1722         WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
1723         DAG_relations_tag_update(CTX_data_main(C));
1724
1725         return OPERATOR_FINISHED;
1726 }
1727  
1728 static void ANIM_OT_channels_delete(wmOperatorType *ot)
1729 {
1730         /* identifiers */
1731         ot->name = "Delete Channels";
1732         ot->idname = "ANIM_OT_channels_delete";
1733         ot->description = "Delete all selected animation channels";
1734         
1735         /* api callbacks */
1736         ot->exec = animchannels_delete_exec;
1737         ot->poll = animedit_poll_channels_active;
1738         
1739         /* flags */
1740         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1741 }
1742
1743 /* ********************** Set Flags Operator *********************** */
1744
1745 /* defines for setting animation-channel flags */
1746 static EnumPropertyItem prop_animchannel_setflag_types[] = {
1747         {ACHANNEL_SETFLAG_TOGGLE, "TOGGLE", 0, "Toggle", ""},
1748         {ACHANNEL_SETFLAG_CLEAR, "DISABLE", 0, "Disable", ""},
1749         {ACHANNEL_SETFLAG_ADD, "ENABLE", 0, "Enable", ""},
1750         {ACHANNEL_SETFLAG_INVERT, "INVERT", 0, "Invert", ""},
1751         {0, NULL, 0, NULL, NULL}
1752 };
1753
1754 /* defines for set animation-channel settings */
1755 // TODO: could add some more types, but those are really quite dependent on the mode...
1756 static EnumPropertyItem prop_animchannel_settings_types[] = {
1757         {ACHANNEL_SETTING_PROTECT, "PROTECT", 0, "Protect", ""},
1758         {ACHANNEL_SETTING_MUTE, "MUTE", 0, "Mute", ""},
1759         {0, NULL, 0, NULL, NULL}
1760 };
1761
1762
1763 /* ------------------- */
1764
1765 /* Set/clear a particular flag (setting) for all selected + visible channels 
1766  *      setting: the setting to modify
1767  *      mode: eAnimChannels_SetFlag
1768  *      onlysel: only selected channels get the flag set
1769  */
1770 // TODO: enable a setting which turns flushing on/off?
1771 static void setflag_anim_channels(bAnimContext *ac, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode, bool onlysel, bool flush)
1772 {
1773         ListBase anim_data = {NULL, NULL};
1774         ListBase all_data = {NULL, NULL};
1775         bAnimListElem *ale;
1776         int filter;
1777         
1778         /* filter data that we need if flush is on */
1779         if (flush) {
1780                 /* get list of all channels that selection may need to be flushed to 
1781                  * - hierarchy visibility needs to be ignored so that settings can get flushed
1782                  *   "down" inside closed containers
1783                  */
1784                 filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS;
1785                 ANIM_animdata_filter(ac, &all_data, filter, ac->data, ac->datatype);
1786         }
1787         
1788         /* filter data that we're working on 
1789          * - hierarchy matters if we're doing this from the channels region
1790          *   since we only want to apply this to channels we can "see", 
1791          *   and have these affect their relatives
1792          * - but for Graph Editor, this gets used also from main region
1793          *   where hierarchy doesn't apply [#21276]
1794          */
1795         if ((ac->spacetype == SPACE_IPO) && (ac->regiontype != RGN_TYPE_CHANNELS)) {
1796                 /* graph editor (case 2) */
1797                 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_NODUPLIS);
1798         }
1799         else {
1800                 /* standard case */
1801                 filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS);
1802         }
1803         if (onlysel) filter |= ANIMFILTER_SEL;
1804         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
1805         
1806         /* if toggling, check if disable or enable */
1807         if (mode == ACHANNEL_SETFLAG_TOGGLE) {
1808                 /* default to turn all on, unless we encounter one that's on... */
1809                 mode = ACHANNEL_SETFLAG_ADD;
1810                 
1811                 /* see if we should turn off instead... */
1812                 for (ale = anim_data.first; ale; ale = ale->next) {
1813                         /* set the setting in the appropriate way (if available) */
1814                         if (ANIM_channel_setting_get(ac, ale, setting) > 0) {
1815                                 mode = ACHANNEL_SETFLAG_CLEAR;
1816                                 break;
1817                         }
1818                 }
1819         }
1820         
1821         /* apply the setting */
1822         for (ale = anim_data.first; ale; ale = ale->next) {
1823                 /* skip channel if setting is not available */
1824                 if (ANIM_channel_setting_get(ac, ale, setting) == -1)
1825                         continue;
1826                 
1827                 /* set the setting in the appropriate way */
1828                 ANIM_channel_setting_set(ac, ale, setting, mode);
1829                 
1830                 /* if flush status... */
1831                 if (flush)
1832                         ANIM_flush_setting_anim_channels(ac, &all_data, ale, setting, mode);
1833         }
1834         
1835         ANIM_animdata_freelist(&anim_data);
1836         BLI_freelistN(&all_data);
1837 }
1838
1839 /* ------------------- */
1840
1841 static int animchannels_setflag_exec(bContext *C, wmOperator *op)
1842 {
1843         bAnimContext ac;
1844         eAnimChannel_Settings setting;
1845         eAnimChannels_SetFlag mode;
1846         bool flush = true;
1847         
1848         /* get editor data */
1849         if (ANIM_animdata_get_context(C, &ac) == 0)
1850                 return OPERATOR_CANCELLED;
1851                 
1852         /* mode (eAnimChannels_SetFlag), setting (eAnimChannel_Settings) */
1853         mode = RNA_enum_get(op->ptr, "mode");
1854         setting = RNA_enum_get(op->ptr, "type");
1855         
1856         /* check if setting is flushable */
1857         if (setting == ACHANNEL_SETTING_EXPAND)
1858                 flush = false;
1859         
1860         /* modify setting 
1861          *      - only selected channels are affected
1862          */
1863         setflag_anim_channels(&ac, setting, mode, true, flush);
1864         
1865         /* send notifier that things have changed */
1866         WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
1867         
1868         return OPERATOR_FINISHED;
1869 }
1870
1871 /* duplicate of 'ANIM_OT_channels_setting_toggle' for menu title only, weak! */
1872 static void ANIM_OT_channels_setting_enable(wmOperatorType *ot)
1873 {
1874         PropertyRNA *prop;
1875         
1876         /* identifiers */
1877         ot->name = "Enable Channel Setting";
1878         ot->idname = "ANIM_OT_channels_setting_enable";
1879         ot->description = "Enable specified setting on all selected animation channels";
1880         
1881         /* api callbacks */
1882         ot->invoke = WM_menu_invoke;
1883         ot->exec = animchannels_setflag_exec;
1884         ot->poll = animedit_poll_channels_active;
1885         
1886         /* flags */
1887         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1888         
1889         /* props */
1890         /* flag-setting mode */
1891         prop = RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_ADD, "Mode", "");
1892         RNA_def_property_flag(prop, PROP_HIDDEN);
1893         /* setting to set */
1894         ot->prop = RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
1895 }
1896 /* duplicate of 'ANIM_OT_channels_setting_toggle' for menu title only, weak! */
1897 static void ANIM_OT_channels_setting_disable(wmOperatorType *ot)
1898 {
1899         PropertyRNA *prop;
1900         
1901         /* identifiers */
1902         ot->name = "Disable Channel Setting";
1903         ot->idname = "ANIM_OT_channels_setting_disable";
1904         ot->description = "Disable specified setting on all selected animation channels";
1905         
1906         /* api callbacks */
1907         ot->invoke = WM_menu_invoke;
1908         ot->exec = animchannels_setflag_exec;
1909         ot->poll = animedit_poll_channels_active;
1910         
1911         /* flags */
1912         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1913         
1914         /* props */
1915         /* flag-setting mode */
1916         prop = RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_CLEAR, "Mode", "");
1917         RNA_def_property_flag(prop, PROP_HIDDEN); /* internal hack - don't expose */
1918         /* setting to set */
1919         ot->prop = RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
1920 }
1921
1922 static void ANIM_OT_channels_setting_toggle(wmOperatorType *ot)
1923 {
1924         PropertyRNA *prop;
1925         
1926         /* identifiers */
1927         ot->name = "Toggle Channel Setting";
1928         ot->idname = "ANIM_OT_channels_setting_toggle";
1929         ot->description = "Toggle specified setting on all selected animation channels";
1930         
1931         /* api callbacks */
1932         ot->invoke = WM_menu_invoke;
1933         ot->exec = animchannels_setflag_exec;
1934         ot->poll = animedit_poll_channels_active;
1935         
1936         /* flags */
1937         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1938         
1939         /* props */
1940         /* flag-setting mode */
1941         prop = RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", "");
1942         RNA_def_property_flag(prop, PROP_HIDDEN); /* internal hack - don't expose */
1943         /* setting to set */
1944         ot->prop = RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, 0, "Type", "");
1945 }
1946
1947 static void ANIM_OT_channels_editable_toggle(wmOperatorType *ot)
1948 {
1949         PropertyRNA *prop;
1950         
1951         /* identifiers */
1952         ot->name = "Toggle Channel Editability";
1953         ot->idname = "ANIM_OT_channels_editable_toggle";
1954         ot->description = "Toggle editability of selected channels";
1955         
1956         /* api callbacks */
1957         ot->exec = animchannels_setflag_exec;
1958         ot->poll = animedit_poll_channels_active;
1959         
1960         /* flags */
1961         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1962         
1963         /* props */
1964         /* flag-setting mode */
1965         RNA_def_enum(ot->srna, "mode", prop_animchannel_setflag_types, ACHANNEL_SETFLAG_TOGGLE, "Mode", "");
1966         /* setting to set */
1967         prop = RNA_def_enum(ot->srna, "type", prop_animchannel_settings_types, ACHANNEL_SETTING_PROTECT, "Type", "");
1968         RNA_def_property_flag(prop, PROP_HIDDEN); /* internal hack - don't expose */
1969 }
1970
1971 /* ********************** Expand Channels Operator *********************** */
1972
1973 static int animchannels_expand_exec(bContext *C, wmOperator *op)
1974 {
1975         bAnimContext ac;
1976         bool onlysel = true;
1977         
1978         /* get editor data */
1979         if (ANIM_animdata_get_context(C, &ac) == 0)
1980                 return OPERATOR_CANCELLED;
1981                 
1982         /* only affect selected channels? */
1983         if (RNA_boolean_get(op->ptr, "all"))
1984                 onlysel = false;
1985         
1986         /* modify setting */
1987         setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_ADD, onlysel, false);
1988         
1989         /* send notifier that things have changed */
1990         WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
1991         
1992         return OPERATOR_FINISHED;
1993 }
1994
1995 static void ANIM_OT_channels_expand(wmOperatorType *ot)
1996 {
1997         /* identifiers */
1998         ot->name = "Expand Channels";
1999         ot->idname = "ANIM_OT_channels_expand";
2000         ot->description = "Expand (i.e. open) all selected expandable animation channels";
2001         
2002         /* api callbacks */
2003         ot->exec = animchannels_expand_exec;
2004         ot->poll = animedit_poll_channels_active;
2005         
2006         /* flags */
2007         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2008         
2009         /* props */
2010         ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All", "Expand all channels (not just selected ones)");
2011 }
2012
2013 /* ********************** Collapse Channels Operator *********************** */
2014
2015 static int animchannels_collapse_exec(bContext *C, wmOperator *op)
2016 {
2017         bAnimContext ac;
2018         bool onlysel = true;
2019         
2020         /* get editor data */
2021         if (ANIM_animdata_get_context(C, &ac) == 0)
2022                 return OPERATOR_CANCELLED;
2023                 
2024         /* only affect selected channels? */
2025         if (RNA_boolean_get(op->ptr, "all"))
2026                 onlysel = false;
2027         
2028         /* modify setting */
2029         setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_CLEAR, onlysel, false);
2030         
2031         /* send notifier that things have changed */
2032         WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
2033         
2034         return OPERATOR_FINISHED;
2035 }
2036
2037 static void ANIM_OT_channels_collapse(wmOperatorType *ot)
2038 {
2039         /* identifiers */
2040         ot->name = "Collapse Channels";
2041         ot->idname = "ANIM_OT_channels_collapse";
2042         ot->description = "Collapse (i.e. close) all selected expandable animation channels";
2043         
2044         /* api callbacks */
2045         ot->exec = animchannels_collapse_exec;
2046         ot->poll = animedit_poll_channels_active;
2047         
2048         /* flags */
2049         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2050         
2051         /* props */
2052         ot->prop = RNA_def_boolean(ot->srna, "all", true, "All", "Collapse all channels (not just selected ones)");
2053 }
2054
2055 /* ************ Remove All "Empty" AnimData Blocks Operator ********* */
2056 /* We define "empty" AnimData blocks here as those which have all 3 of criteria:
2057  *  1) No active action OR that active actions are empty
2058  *     Assuming that all legitimate entries will have an action,
2059  *     and that empty actions
2060  *  2) No NLA Tracks + NLA Strips
2061  *     Assuming that users haven't set up any of these as "placeholders"
2062  *     for convenience sake, and that most that exist were either unintentional
2063  *     or are no longer wanted
2064  *  3) No drivers
2065  */
2066  
2067 static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op))
2068 {
2069         bAnimContext ac;
2070         
2071         ListBase anim_data = {NULL, NULL};
2072         bAnimListElem *ale;
2073         int filter;
2074         
2075         /* get editor data */
2076         if (ANIM_animdata_get_context(C, &ac) == 0)
2077                 return OPERATOR_CANCELLED;
2078         
2079         /* get animdata blocks */
2080         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA);
2081         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2082         
2083         for (ale = anim_data.first; ale; ale = ale->next) {
2084                 ID *id = ale->id;
2085                 AnimData *adt = ale->data;
2086                 
2087                 bool action_empty  = false;
2088                 bool nla_empty     = false;
2089                 bool drivers_empty = false;
2090                 
2091                 /* sanity checks */
2092                 BLI_assert((id != NULL) && (adt != NULL));
2093                 
2094                 /* check if this is "empty" and can be deleted */
2095                 /* (For now, there are only these 3 criteria) */
2096                 
2097                 /* 1) Active Action is missing or empty */
2098                 if (ELEM(NULL, adt->action, adt->action->curves.first)) {
2099                         action_empty = true;
2100                 }
2101                 else {
2102                         /* TODO: check for keyframe + fmodifier data on these too */
2103                 }
2104                 
2105                 /* 2) No NLA Tracks and/or NLA Strips */
2106                 if (adt->nla_tracks.first == NULL) {
2107                         nla_empty = true;
2108                 }
2109                 else {
2110                         NlaTrack *nlt;
2111                         
2112                         /* empty tracks? */
2113                         for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
2114                                 if (nlt->strips.first) {
2115                                         /* stop searching, as we found one that actually had stuff we don't want lost 
2116                                          * NOTE: nla_empty gets reset to false, as a previous track may have been empty
2117                                          */
2118                                         nla_empty = false;
2119                                         break;
2120                                 }
2121                                 else if (nlt->strips.first == NULL) {
2122                                         /* this track is empty, but another one may still have stuff in it, so can't break yet */
2123                                         nla_empty = true;
2124                                 }
2125                         }
2126                 }
2127                 
2128                 /* 3) Drivers */
2129                 drivers_empty = (adt->drivers.first == NULL);
2130                 
2131                 
2132                 /* remove AnimData? */
2133                 if (action_empty && nla_empty && drivers_empty) {
2134                         BKE_animdata_free(id, true);
2135                 }
2136         }
2137         
2138         /* free temp data */
2139         ANIM_animdata_freelist(&anim_data);
2140         
2141         /* send notifier that things have changed */
2142         WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
2143         
2144         return OPERATOR_FINISHED;
2145 }
2146
2147 static void ANIM_OT_channels_clean_empty(wmOperatorType *ot)
2148 {
2149         /* identifiers */
2150         ot->name = "Remove Empty Animation Data";
2151         ot->idname = "ANIM_OT_channels_clean_empty";
2152         ot->description = "Delete all empty animation data containers from visible data-blocks";
2153         
2154         /* api callbacks */
2155         ot->exec = animchannels_clean_empty_exec;
2156         ot->poll = animedit_poll_channels_nla_tweakmode_off;
2157         
2158         /* flags */
2159         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2160 }
2161
2162 /* ******************* Reenable Disabled Operator ******************* */
2163
2164 static int animchannels_enable_poll(bContext *C)
2165 {
2166         ScrArea *sa = CTX_wm_area(C);
2167         
2168         /* channels region test */
2169         /* TODO: could enhance with actually testing if channels region? */
2170         if (ELEM(NULL, sa, CTX_wm_region(C)))
2171                 return 0;
2172                 
2173         /* animation editor test - Action/Dopesheet/etc. and Graph only */
2174         if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO) == 0)
2175                 return 0;
2176                 
2177         return 1;
2178 }
2179
2180 static int animchannels_enable_exec(bContext *C, wmOperator *UNUSED(op))
2181 {
2182         bAnimContext ac;
2183         
2184         ListBase anim_data = {NULL, NULL};
2185         bAnimListElem *ale;
2186         int filter;
2187         
2188         /* get editor data */
2189         if (ANIM_animdata_get_context(C, &ac) == 0)
2190                 return OPERATOR_CANCELLED;
2191         
2192         /* filter data */
2193         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS);
2194         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
2195         
2196         /* loop through filtered data and clean curves */
2197         for (ale = anim_data.first; ale; ale = ale->next) {
2198                 FCurve *fcu = (FCurve *)ale->data;
2199                 
2200                 /* remove disabled flags from F-Curves */
2201                 fcu->flag &= ~FCURVE_DISABLED;
2202                 
2203                 /* for drivers, let's do the same too */
2204                 if (fcu->driver)
2205                         fcu->driver->flag &= ~DRIVER_FLAG_INVALID;
2206                         
2207                 /* tag everything for updates - in particular, this is needed to get drivers working again */
2208                 ale->update |= ANIM_UPDATE_DEPS;
2209         }
2210         
2211         ANIM_animdata_update(&ac, &anim_data);
2212         ANIM_animdata_freelist(&anim_data);
2213                 
2214         /* send notifier that things have changed */
2215         WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
2216         
2217         return OPERATOR_FINISHED;
2218 }
2219
2220 static void ANIM_OT_channels_fcurves_enable(wmOperatorType *ot)
2221 {
2222         /* identifiers */
2223         ot->name = "Revive Disabled F-Curves";
2224         ot->idname = "ANIM_OT_channels_fcurves_enable";
2225         ot->description = "Clears 'disabled' tag from all F-Curves to get broken F-Curves working again";
2226         
2227         /* api callbacks */
2228         ot->exec = animchannels_enable_exec;
2229         ot->poll = animchannels_enable_poll;
2230         
2231         /* flags */
2232         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2233 }
2234
2235 /* ****************** Find / Set Filter Operator ******************** */
2236
2237 /* XXX: make this generic? */
2238 static int animchannels_find_poll(bContext *C)
2239 {
2240         ScrArea *sa = CTX_wm_area(C);
2241         
2242         if (sa == NULL)
2243                 return 0;
2244         
2245         /* animation editor with dopesheet */
2246         return ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA);
2247 }
2248
2249 /* find_invoke() - Get initial channels */
2250 static int animchannels_find_invoke(bContext *C, wmOperator *op, const wmEvent *evt)
2251 {
2252         bAnimContext ac;
2253         
2254         /* get editor data */
2255         if (ANIM_animdata_get_context(C, &ac) == 0)
2256                 return OPERATOR_CANCELLED;
2257         
2258         /* set initial filter text, and enable filter */
2259         RNA_string_set(op->ptr, "query", ac.ads->searchstr);
2260         
2261         /* defer to popup */
2262         return WM_operator_props_popup(C, op, evt);
2263 }
2264
2265 /* find_exec() -  Called to set the value */
2266 static int animchannels_find_exec(bContext *C, wmOperator *op)
2267 {
2268         bAnimContext ac;
2269         
2270         /* get editor data */
2271         if (ANIM_animdata_get_context(C, &ac) == 0)
2272                 return OPERATOR_CANCELLED;
2273         
2274         /* update filter text, and ensure that filter is enabled if there's something there
2275          * NOTE: we turn the filter off if there's nothing (this is a quick shortcut for dismissing)
2276          */
2277         RNA_string_get(op->ptr, "query", ac.ads->searchstr);
2278         
2279         if (ac.ads->searchstr[0]) {
2280                 ac.ads->filterflag |= ADS_FILTER_BY_FCU_NAME;
2281         }
2282         else {
2283                 ac.ads->filterflag &= ~ADS_FILTER_BY_FCU_NAME;
2284         }
2285         
2286         /* redraw */
2287         WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
2288         
2289         return OPERATOR_FINISHED;
2290 }
2291
2292 static void ANIM_OT_channels_find(wmOperatorType *ot)
2293 {
2294         /* identifiers */
2295         ot->name = "Find Channels";
2296         ot->idname = "ANIM_OT_channels_find";
2297         ot->description = "Filter the set of channels shown to only include those with matching names";
2298         
2299         /* callbacks */
2300         ot->invoke = animchannels_find_invoke;
2301         ot->exec = animchannels_find_exec;
2302         ot->poll = animchannels_find_poll;
2303         
2304         /* flags */
2305         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2306         
2307         /* properties */
2308         ot->prop = RNA_def_string(ot->srna, "query", "Query", sizeof(((bDopeSheet *)NULL)->searchstr), "", "Text to search for in channel names");
2309 }
2310
2311 /* ********************** Select All Operator *********************** */
2312
2313 static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
2314 {
2315         bAnimContext ac;
2316         
2317         /* get editor data */
2318         if (ANIM_animdata_get_context(C, &ac) == 0)
2319                 return OPERATOR_CANCELLED;
2320                 
2321         /* 'standard' behavior - check if selected, then apply relevant selection */
2322         if (RNA_boolean_get(op->ptr, "invert"))
2323                 ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_INVERT);
2324         else
2325                 ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, true, ACHANNEL_SETFLAG_ADD);
2326         
2327         /* send notifier that things have changed */
2328         WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
2329         
2330         return OPERATOR_FINISHED;
2331 }
2332  
2333 static void ANIM_OT_channels_select_all_toggle(wmOperatorType *ot)
2334 {
2335         /* identifiers */
2336         ot->name = "Select All";
2337         ot->idname = "ANIM_OT_channels_select_all_toggle";
2338         ot->description = "Toggle selection of all animation channels";
2339         
2340         /* api callbacks */
2341         ot->exec = animchannels_deselectall_exec;
2342         ot->poll = animedit_poll_channels_nla_tweakmode_off;
2343         
2344         /* flags */
2345         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2346         
2347         /* props */
2348         ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "");
2349 }
2350
2351 /* ******************** Borderselect Operator *********************** */
2352
2353 static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selectmode)
2354 {
2355         ListBase anim_data = {NULL, NULL};
2356         bAnimListElem *ale;
2357         int filter;
2358         
2359         SpaceNla *snla = (SpaceNla *)ac->sl;
2360         View2D *v2d = &ac->ar->v2d;
2361         rctf rectf;
2362         float ymin, ymax;
2363         
2364         /* set initial y extents */
2365         if (ac->datatype == ANIMCONT_NLA) {
2366                 ymin = (float)(-NLACHANNEL_HEIGHT(snla));
2367                 ymax = 0.0f;
2368         }
2369         else {
2370                 ymin = 0.0f;
2371                 ymax = (float)(-ACHANNEL_HEIGHT(ac));
2372         }
2373         
2374         /* convert border-region to view coordinates */
2375         UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin + 2, &rectf.xmin, &rectf.ymin);
2376         UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax - 2, &rectf.xmax, &rectf.ymax);
2377         
2378         /* filter data */
2379         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
2380         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
2381         
2382         /* loop over data, doing border select */
2383         for (ale = anim_data.first; ale; ale = ale->next) {
2384                 if (ac->datatype == ANIMCONT_NLA)
2385                         ymin = ymax - NLACHANNEL_STEP(snla);
2386                 else
2387                         ymin = ymax - ACHANNEL_STEP(ac);
2388                 
2389                 /* if channel is within border-select region, alter it */
2390                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
2391                         /* set selection flags only */
2392                         ANIM_channel_setting_set(ac, ale, ACHANNEL_SETTING_SELECT, selectmode);
2393                         
2394                         /* type specific actions */
2395                         switch (ale->type) {
2396                                 case ANIMTYPE_GROUP:
2397                                 {
2398                                         bActionGroup *agrp = (bActionGroup *)ale->data;
2399                                         
2400                                         /* Armatures-Specific Feature:
2401                                          * See mouse_anim_channels() -> ANIMTYPE_GROUP case for more details (T38737)
2402                                          */
2403                                         if ((ac->ads->filterflag & ADS_FILTER_ONLYSEL) == 0) {
2404                                                 if ((ale->id) && (GS(ale->id->name) == ID_OB)) {
2405                                                         Object *ob = (Object *)ale->id;
2406                                                         
2407                                                         if (ob->type == OB_ARMATURE) {
2408                                                                 /* Assume for now that any group with corresponding name is what we want
2409                                                                  * (i.e. for an armature whose location is animated, things would break
2410                                                                  * if the user were to add a bone named "Location").
2411                                                                  *
2412                                                                  * TODO: check the first F-Curve or so to be sure...
2413                                                                  */
2414                                                                 bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name);
2415                                                                 
2416                                                                 if (agrp->flag & AGRP_SELECTED) {
2417                                                                         ED_pose_bone_select(ob, pchan, true);
2418                                                                 }
2419                                                                 else {
2420                                                                         ED_pose_bone_select(ob, pchan, false);
2421                                                                 }
2422                                                         }
2423                                                 }
2424                                         }
2425                                         
2426                                         /* always clear active flag after doing this */
2427                                         agrp->flag &= ~AGRP_ACTIVE;
2428                                         break;
2429                                 }
2430                                 case ANIMTYPE_NLATRACK:
2431                                 {
2432                                         NlaTrack *nlt = (NlaTrack *)ale->data;
2433                                         
2434                                         /* for now, it's easier just to do this here manually, as defining a new type 
2435                                          * currently adds complications when doing other stuff 
2436                                          */
2437                                         ACHANNEL_SET_FLAG(nlt, selectmode, NLATRACK_SELECTED);
2438                                         break;
2439                                 }
2440                         }
2441                 }
2442                 
2443                 /* set minimum extent to be the maximum of the next channel */
2444                 ymax = ymin;
2445         }
2446         
2447         /* cleanup */
2448         ANIM_animdata_freelist(&anim_data);
2449 }
2450
2451 /* ------------------- */
2452
2453 static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
2454 {
2455         bAnimContext ac;
2456         rcti rect;
2457         short selectmode = 0;
2458         const bool select = !RNA_boolean_get(op->ptr, "deselect");
2459         const bool extend = RNA_boolean_get(op->ptr, "extend");
2460         
2461         /* get editor data */
2462         if (ANIM_animdata_get_context(C, &ac) == 0)
2463                 return OPERATOR_CANCELLED;
2464         
2465         /* get settings from operator */
2466         WM_operator_properties_border_to_rcti(op, &rect);
2467
2468         if (!extend) {
2469                 ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, true, ACHANNEL_SETFLAG_CLEAR);
2470         }
2471
2472         if (select) {
2473                 selectmode = ACHANNEL_SETFLAG_ADD;
2474         }
2475         else {
2476                 selectmode = ACHANNEL_SETFLAG_CLEAR;
2477         }
2478         
2479         /* apply borderselect animation channels */
2480         borderselect_anim_channels(&ac, &rect, selectmode);
2481         
2482         /* send notifier that things have changed */
2483         WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
2484         
2485         return OPERATOR_FINISHED;
2486
2487
2488 static void ANIM_OT_channels_select_border(wmOperatorType *ot)
2489 {
2490         /* identifiers */
2491         ot->name = "Border Select";
2492         ot->idname = "ANIM_OT_channels_select_border";
2493         ot->description = "Select all animation channels within the specified region";
2494         
2495         /* api callbacks */
2496         ot->invoke = WM_gesture_border_invoke;
2497         ot->exec = animchannels_borderselect_exec;
2498         ot->modal = WM_gesture_border_modal;
2499         ot->cancel = WM_gesture_border_cancel;
2500         
2501         ot->poll = animedit_poll_channels_nla_tweakmode_off;
2502         
2503         /* flags */
2504         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2505         
2506         /* rna */
2507         WM_operator_properties_gesture_border_select(ot);
2508 }
2509
2510 /* ******************* Rename Operator ***************************** */
2511 /* Allow renaming some channels by clicking on them */
2512
2513 static bool rename_anim_channels(bAnimContext *ac, int channel_index)
2514 {
2515         ListBase anim_data = {NULL, NULL};
2516         const bAnimChannelType *acf;
2517         bAnimListElem *ale;
2518         int filter;
2519         bool success = false;
2520         
2521         /* get the channel that was clicked on */
2522         /* filter channels */
2523         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
2524         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
2525         
2526         /* get channel from index */
2527         ale = BLI_findlink(&anim_data, channel_index);
2528         if (ale == NULL) {
2529                 /* channel not found */
2530                 if (G.debug & G_DEBUG)
2531                         printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", channel_index);
2532                 
2533                 ANIM_animdata_freelist(&anim_data);
2534                 return false;
2535         }
2536         
2537         /* check that channel can be renamed */
2538         acf = ANIM_channel_get_typeinfo(ale);
2539         if (acf && acf->name_prop) {
2540                 PointerRNA ptr;
2541                 PropertyRNA *prop;
2542                 
2543                 /* ok if we can get name property to edit from this channel */
2544                 if (acf->name_prop(ale, &ptr, &prop)) {
2545                         /* actually showing the rename textfield is done on redraw,
2546                          * so here we just store the index of this channel in the 
2547                          * dopesheet data, which will get utilized when drawing the
2548                          * channel...
2549                          *
2550                          * +1 factor is for backwards compat issues
2551                          */
2552                         if (ac->ads) {
2553                                 ac->ads->renameIndex = channel_index + 1;
2554                                 success = true;
2555                         }
2556                 }
2557         }
2558         
2559         /* free temp data and tag for refresh */
2560         ANIM_animdata_freelist(&anim_data);
2561         ED_region_tag_redraw(ac->ar);
2562         return success;
2563 }
2564
2565 static int animchannels_channel_get(bAnimContext *ac, const int mval[2])
2566 {
2567         ARegion *ar;
2568         View2D *v2d;
2569         int channel_index;
2570         float x, y;
2571         
2572         /* get useful pointers from animation context data */
2573         ar = ac->ar;
2574         v2d = &ar->v2d;
2575         
2576         /* figure out which channel user clicked in 
2577          * Note: although channels technically start at (y = ACHANNEL_FIRST), we need to adjust by half a channel's height
2578          *              so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
2579          *              ACHANNEL_HEIGHT_HALF.
2580          */
2581         UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
2582         
2583         if (ac->datatype == ANIMCONT_NLA) {
2584                 SpaceNla *snla = (SpaceNla *)ac->sl;
2585                 UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index);
2586         }
2587         else {
2588                 UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP(ac), 0, (float)ACHANNEL_HEIGHT_HALF(ac), x, y, NULL, &channel_index);
2589         }
2590
2591         return channel_index;
2592 }
2593
2594 static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
2595 {
2596         bAnimContext ac;
2597         int channel_index;
2598
2599         /* get editor data */
2600         if (ANIM_animdata_get_context(C, &ac) == 0)
2601                 return OPERATOR_CANCELLED;
2602
2603         channel_index = animchannels_channel_get(&ac, event->mval);
2604
2605         /* handle click */
2606         if (rename_anim_channels(&ac, channel_index))
2607                 return OPERATOR_FINISHED;
2608         else
2609                 /* allow event to be handled by selectall operator */
2610                 return OPERATOR_PASS_THROUGH;
2611 }
2612
2613 static void ANIM_OT_channels_rename(wmOperatorType *ot)
2614 {
2615         /* identifiers */
2616         ot->name = "Rename Channels";
2617         ot->idname = "ANIM_OT_channels_rename";
2618         ot->description = "Rename animation channel under mouse";
2619         
2620         /* api callbacks */
2621         ot->invoke = animchannels_rename_invoke;
2622         ot->poll = animedit_poll_channels_active;
2623 }
2624
2625 /* ******************** Mouse-Click Operator *********************** */
2626 /* Handle selection changes due to clicking on channels. Settings will get caught by UI code... */
2627
2628 static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index, short selectmode)
2629 {
2630         ListBase anim_data = {NULL, NULL};
2631         bAnimListElem *ale;
2632         int filter;
2633         int notifierFlags = 0;
2634         
2635         /* get the channel that was clicked on */
2636         /* filter channels */
2637         filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
2638         ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
2639         
2640         /* get channel from index */
2641         ale = BLI_findlink(&anim_data, channel_index);
2642         if (ale == NULL) {
2643                 /* channel not found */
2644                 if (G.debug & G_DEBUG)
2645                         printf("Error: animation channel (index = %d) not found in mouse_anim_channels()\n", channel_index);
2646                 
2647                 ANIM_animdata_freelist(&anim_data);
2648                 return 0;
2649         }
2650
2651         /* selectmode -1 is a special case for ActionGroups only, which selects all of the channels underneath it only... */
2652         /* TODO: should this feature be extended to work with other channel types too? */
2653         if ((selectmode == -1) && (ale->type != ANIMTYPE_GROUP)) {
2654                 /* normal channels should not behave normally in this case */
2655                 ANIM_animdata_freelist(&anim_data);
2656                 return 0;
2657         }
2658
2659         /* action to take depends on what channel we've got */
2660         /* WARNING: must keep this in sync with the equivalent function in nla_channels.c */
2661         switch (ale->type) {
2662                 case ANIMTYPE_SCENE:
2663                 {
2664                         Scene *sce = (Scene *)ale->data;
2665                         AnimData *adt = sce->adt;
2666                         
2667                         /* set selection status */
2668                         if (selectmode == SELECT_INVERT) {
2669                                 /* swap select */
2670                                 sce->flag ^= SCE_DS_SELECTED;
2671                                 if (adt) adt->flag ^= ADT_UI_SELECTED;
2672                         }
2673                         else {
2674                                 sce->flag |= SCE_DS_SELECTED;
2675                                 if (adt) adt->flag |= ADT_UI_SELECTED;
2676                         }
2677                         
2678                         notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
2679                         break;
2680                 }
2681                 case ANIMTYPE_OBJECT:
2682                 {
2683                         bDopeSheet *ads = (bDopeSheet *)ac->data;
2684                         Scene *sce = (Scene *)ads->source;
2685                         Base *base = (Base *)ale->data;
2686                         Object *ob = base->object;
2687                         AnimData *adt = ob->adt;
2688                         
2689                         /* set selection status */
2690                         if (selectmode == SELECT_INVERT) {
2691                                 /* swap select */
2692                                 base->flag ^= SELECT;
2693                                 ob->flag = base->flag;
2694                                 
2695                                 if (adt) adt->flag ^= ADT_UI_SELECTED;
2696                         }
2697                         else {
2698                                 Base *b;
2699                                 
2700                                 /* deselect all */
2701                                 /* TODO: should this deselect all other types of channels too? */
2702                                 for (b = sce->base.first; b; b = b->next) {
2703                                         b->flag &= ~SELECT;
2704                                         b->object->flag = b->flag;
2705                                         if (b->object->adt) b->object->adt->flag &= ~(ADT_UI_SELECTED | ADT_UI_ACTIVE);
2706                                 }
2707                                 
2708                                 /* select object now */
2709                                 base->flag |= SELECT;
2710                                 ob->flag |= SELECT;
2711                                 if (adt) adt->flag |= ADT_UI_SELECTED;
2712                         }
2713                         
2714                         /* change active object - regardless of whether it is now selected [T37883] */
2715                         ED_base_object_activate(C, base); /* adds notifier */
2716                         
2717                         if ((adt) && (adt->flag & ADT_UI_SELECTED))
2718                                 adt->flag |= ADT_UI_ACTIVE;
2719                         
2720                         /* ensure we exit editmode on whatever object was active before to avoid getting stuck there - T48747 */
2721                         if (ob != sce->obedit)
2722                                 ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
2723                         
2724                         notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
2725                         break;
2726                 }
2727                 case ANIMTYPE_FILLACTD: /* Action Expander */
2728                 case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
2729                 case ANIMTYPE_DSLAM:
2730                 case ANIMTYPE_DSCAM:
2731                 case ANIMTYPE_DSCACHEFILE:
2732                 case ANIMTYPE_DSCUR:
2733                 case ANIMTYPE_DSSKEY:
2734                 case ANIMTYPE_DSWOR:
2735                 case ANIMTYPE_DSPART:
2736                 case ANIMTYPE_DSMBALL:
2737                 case ANIMTYPE_DSARM:
2738                 case ANIMTYPE_DSMESH:
2739                 case ANIMTYPE_DSNTREE:
2740                 case ANIMTYPE_DSTEX:
2741                 case ANIMTYPE_DSLAT:
2742                 case ANIMTYPE_DSLINESTYLE:
2743                 case ANIMTYPE_DSSPK:
2744                 case ANIMTYPE_DSGPENCIL:
2745                 case ANIMTYPE_DSMCLIP:
2746                 {
2747                         /* sanity checking... */
2748                         if (ale->adt) {
2749                                 /* select/deselect */
2750                                 if (selectmode == SELECT_INVERT) {
2751                                         /* inverse selection status of this AnimData block only */
2752                                         ale->adt->flag ^= ADT_UI_SELECTED;
2753                                 }
2754                                 else {
2755                                         /* select AnimData block by itself */
2756                                         ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
2757                                         ale->adt->flag |= ADT_UI_SELECTED;
2758                                 }
2759                                 
2760                                 /* set active? */
2761                                 if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
2762                                         ale->adt->flag |= ADT_UI_ACTIVE;
2763                         }
2764                         
2765                         notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
2766                         break;
2767                 }
2768                 case ANIMTYPE_GROUP: 
2769                 {
2770                         bActionGroup *agrp = (bActionGroup *)ale->data;
2771                         
2772                         Object *ob = NULL;
2773                         bPoseChannel *pchan = NULL;
2774                         
2775                         
2776                         /* Armatures-Specific Feature:
2777                          * Since groups are used to collect F-Curves of the same Bone by default
2778                          * (via Keying Sets) so that they can be managed better, we try to make
2779                          * things here easier for animators by mapping group selection to bone
2780                          * selection. 
2781                          *
2782                          * Only do this if "Only Selected" dopesheet filter is not active, or else it
2783                          * becomes too unpredictable/tricky to manage
2784                          */
2785                         if ((ac->ads->filterflag & ADS_FILTER_ONLYSEL) == 0) {
2786                                 if ((ale->id) && (GS(ale->id->name) == ID_OB)) {
2787                                         ob = (Object *)ale->id;
2788                                         
2789                                         if (ob->type == OB_ARMATURE) {
2790                                                 /* Assume for now that any group with corresponding name is what we want
2791                                                  * (i.e. for an armature whose location is animated, things would break
2792                                                  * if the user were to add a bone named "Location").
2793                                                  *
2794                                                  * TODO: check the first F-Curve or so to be sure...
2795                                                  */
2796                                                 pchan = BKE_pose_channel_find_name(ob->pose, agrp->name);
2797                                         }       
2798                                 }
2799                         }
2800                         
2801                         /* select/deselect group */
2802                         if (selectmode == SELECT_INVERT) {
2803                                 /* inverse selection status of this group only */
2804                                 agrp->flag ^= AGRP_SELECTED;
2805                         }
2806                         else if (selectmode == -1) {
2807                                 /* select all in group (and deselect everthing else) */
2808                                 FCurve *fcu;
2809                                 
2810                                 /* deselect all other channels */
2811                                 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
2812                                 if (pchan) ED_pose_de_selectall(ob, SEL_DESELECT, false);
2813                                 
2814                                 /* only select channels in group and group itself */
2815                                 for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next)
2816                                         fcu->flag |= FCURVE_SELECTED;
2817                                 agrp->flag |= AGRP_SELECTED;
2818                         }
2819                         else {
2820                                 /* select group by itself */
2821                                 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
2822                                 if (pchan) ED_pose_de_selectall(ob, SEL_DESELECT, false);
2823                                 
2824                                 agrp->flag |= AGRP_SELECTED;
2825                         }
2826                         
2827                         /* if group is selected now, make group the 'active' one in the visible list */
2828                         if (agrp->flag & AGRP_SELECTED) {
2829                                 ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, agrp, ANIMTYPE_GROUP);
2830                                 if (pchan) ED_pose_bone_select(ob, pchan, true);
2831                         }
2832                         else {
2833                                 ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, NULL, ANIMTYPE_GROUP);
2834                                 if (pchan) ED_pose_bone_select(ob, pchan, false);
2835                         }
2836                                 
2837                         notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
2838                         break;
2839                 }
2840                 case ANIMTYPE_FCURVE:
2841                 case ANIMTYPE_NLACURVE:
2842                 {
2843                         FCurve *fcu = (FCurve *)ale->data;
2844                         
2845                         /* select/deselect */
2846                         if (selectmode == SELECT_INVERT) {
2847                                 /* inverse selection status of this F-Curve only */
2848                                 fcu->flag ^= FCURVE_SELECTED;
2849                         }
2850                         else {
2851                                 /* select F-Curve by itself */
2852                                 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
2853                                 fcu->flag |= FCURVE_SELECTED;
2854                         }
2855                         
2856                         /* if F-Curve is selected now, make F-Curve the 'active' one in the visible list */
2857                         if (fcu->flag & FCURVE_SELECTED)
2858                                 ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, fcu, ale->type);
2859                                 
2860                         notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
2861                         break;
2862                 }
2863                 case ANIMTYPE_SHAPEKEY: 
2864                 {
2865                         KeyBlock *kb = (KeyBlock *)ale->data;
2866                         
2867                         /* select/deselect */
2868                         if (selectmode == SELECT_INVERT) {
2869                                 /* inverse selection status of this ShapeKey only */
2870                                 kb->flag ^= KEYBLOCK_SEL;
2871                         }
2872                         else {
2873                                 /* select ShapeKey by itself */
2874                                 ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
2875                                 kb->flag |= KEYBLOCK_SEL;
2876                         }
2877                                 
2878                         notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
2879                         break;
2880                 }
2881                 case ANIMTYPE_NLACONTROLS:
2882                 {
2883                         AnimData *adt = (AnimData *)ale->data;
2884                         
2885                         /* toggle expand
2886                          *   - Although the triangle widget already allows this, since there's nothing else that can be done here now,
2887                          *     let's just use it for easier expand/collapse for now
2888                          */
2889                         adt->flag ^= ADT_NLA_SKEYS_COLLAPSED;
2890                         
2891                         notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
2892                         break;
2893                 }