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