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