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