Merge branch 'blender2.7'
[blender.git] / source / blender / editors / space_nla / nla_channels.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup spnla
22  */
23
24 #include <string.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <math.h>
28
29 #include "DNA_anim_types.h"
30 #include "DNA_object_types.h"
31 #include "DNA_scene_types.h"
32
33 #include "BLI_blenlib.h"
34 #include "BLI_utildefines.h"
35
36 #include "BKE_animsys.h"
37 #include "BKE_nla.h"
38 #include "BKE_context.h"
39 #include "BKE_global.h"
40 #include "BKE_scene.h"
41 #include "BKE_screen.h"
42 #include "BKE_report.h"
43
44 #include "ED_anim_api.h"
45 #include "ED_keyframes_edit.h"
46 #include "ED_object.h"
47 #include "ED_screen.h"
48
49 #include "RNA_access.h"
50 #include "RNA_define.h"
51
52 #include "WM_api.h"
53 #include "WM_types.h"
54
55 #include "DEG_depsgraph.h"
56 #include "DEG_depsgraph_build.h"
57
58 #include "UI_view2d.h"
59
60 #include "nla_intern.h"  // own include
61
62 /* *********************************************** */
63 /* Operators for NLA channels-list which need to be different
64  * from the standard Animation Editor ones */
65
66 /* ******************** Mouse-Click Operator *********************** */
67 /* Depending on the channel that was clicked on, the mouse click will activate whichever
68  * part of the channel is relevant.
69  *
70  * NOTE: eventually, this should probably be phased out when many of these things are replaced with buttons
71  * --> Most channels are now selection only...
72  */
73
74 static int mouse_nla_channels(
75     bContext *C, bAnimContext *ac, float x, int channel_index, short selectmode)
76 {
77   ListBase anim_data = {NULL, NULL};
78   bAnimListElem *ale;
79   int filter;
80
81   View2D *v2d = &ac->ar->v2d;
82   int notifierFlags = 0;
83
84   /* get the channel that was clicked on */
85   /* filter channels */
86   filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
87   ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
88
89   /* get channel from index */
90   ale = BLI_findlink(&anim_data, channel_index);
91   if (ale == NULL) {
92     /* channel not found */
93     if (G.debug & G_DEBUG)
94       printf("Error: animation channel (index = %d) not found in mouse_anim_channels()\n",
95              channel_index);
96
97     ANIM_animdata_freelist(&anim_data);
98     return 0;
99   }
100
101   /* action to take depends on what channel we've got */
102   // WARNING: must keep this in sync with the equivalent function in anim_channels_edit.c
103   switch (ale->type) {
104     case ANIMTYPE_SCENE: {
105       Scene *sce = (Scene *)ale->data;
106       AnimData *adt = sce->adt;
107
108       /* set selection status */
109       if (selectmode == SELECT_INVERT) {
110         /* swap select */
111         sce->flag ^= SCE_DS_SELECTED;
112         if (adt)
113           adt->flag ^= ADT_UI_SELECTED;
114       }
115       else {
116         sce->flag |= SCE_DS_SELECTED;
117         if (adt)
118           adt->flag |= ADT_UI_SELECTED;
119       }
120
121       notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
122       break;
123     }
124     case ANIMTYPE_OBJECT: {
125       ViewLayer *view_layer = ac->view_layer;
126       Base *base = (Base *)ale->data;
127       Object *ob = base->object;
128       AnimData *adt = ob->adt;
129
130       if (nlaedit_is_tweakmode_on(ac) == 0 && (base->flag & BASE_SELECTABLE)) {
131         /* set selection status */
132         if (selectmode == SELECT_INVERT) {
133           /* swap select */
134           ED_object_base_select(base, BA_INVERT);
135           BKE_scene_object_base_flag_sync_from_base(base);
136
137           if (adt)
138             adt->flag ^= ADT_UI_SELECTED;
139         }
140         else {
141           /* deselect all */
142           /* TODO: should this deselect all other types of channels too? */
143           for (Base *b = view_layer->object_bases.first; b; b = b->next) {
144             ED_object_base_select(b, BA_DESELECT);
145             BKE_scene_object_base_flag_sync_from_base(b);
146             if (b->object->adt)
147               b->object->adt->flag &= ~(ADT_UI_SELECTED | ADT_UI_ACTIVE);
148           }
149
150           /* select object now */
151           ED_object_base_select(base, BA_SELECT);
152           BKE_scene_object_base_flag_sync_from_base(base);
153           if (adt)
154             adt->flag |= ADT_UI_SELECTED;
155         }
156
157         /* change active object - regardless of whether it is now selected [T37883] */
158         ED_object_base_activate(C, base); /* adds notifier */
159
160         if ((adt) && (adt->flag & ADT_UI_SELECTED))
161           adt->flag |= ADT_UI_ACTIVE;
162
163         /* notifiers - channel was selected */
164         notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
165       }
166       break;
167     }
168     case ANIMTYPE_FILLACTD: /* Action Expander */
169     case ANIMTYPE_DSMAT:    /* Datablock AnimData Expanders */
170     case ANIMTYPE_DSLAM:
171     case ANIMTYPE_DSCAM:
172     case ANIMTYPE_DSCACHEFILE:
173     case ANIMTYPE_DSCUR:
174     case ANIMTYPE_DSSKEY:
175     case ANIMTYPE_DSWOR:
176     case ANIMTYPE_DSNTREE:
177     case ANIMTYPE_DSPART:
178     case ANIMTYPE_DSMBALL:
179     case ANIMTYPE_DSARM:
180     case ANIMTYPE_DSMESH:
181     case ANIMTYPE_DSTEX:
182     case ANIMTYPE_DSLAT:
183     case ANIMTYPE_DSLINESTYLE:
184     case ANIMTYPE_DSSPK:
185     case ANIMTYPE_DSGPENCIL:
186     case ANIMTYPE_PALETTE: {
187       /* sanity checking... */
188       if (ale->adt) {
189         /* select/deselect */
190         if (selectmode == SELECT_INVERT) {
191           /* inverse selection status of this AnimData block only */
192           ale->adt->flag ^= ADT_UI_SELECTED;
193         }
194         else {
195           /* select AnimData block by itself */
196           ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
197           ale->adt->flag |= ADT_UI_SELECTED;
198         }
199
200         /* set active? */
201         if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
202           ale->adt->flag |= ADT_UI_ACTIVE;
203       }
204
205       notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
206       break;
207     }
208     case ANIMTYPE_NLATRACK: {
209       NlaTrack *nlt = (NlaTrack *)ale->data;
210       AnimData *adt = ale->adt;
211       short offset;
212
213       /* offset for start of channel (on LHS of channel-list) */
214       if (ale->id) {
215         /* special exception for materials and particles */
216         if (ELEM(GS(ale->id->name), ID_MA, ID_PA))
217           offset = 21 + NLACHANNEL_BUTTON_WIDTH;
218         else
219           offset = 14;
220       }
221       else
222         offset = 0;
223
224       if (x >= (v2d->cur.xmax - NLACHANNEL_BUTTON_WIDTH)) {
225         /* toggle protection (only if there's a toggle there) */
226         nlt->flag ^= NLATRACK_PROTECTED;
227
228         /* notifier flags - channel was edited */
229         notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
230       }
231       else if (x >= (v2d->cur.xmax - 2 * NLACHANNEL_BUTTON_WIDTH)) {
232         /* toggle mute */
233         nlt->flag ^= NLATRACK_MUTED;
234
235         /* notifier flags - channel was edited */
236         notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
237         ale->update |= ANIM_UPDATE_DEPS;
238       }
239       else if (x <= ((NLACHANNEL_BUTTON_WIDTH * 2) + offset)) {
240         /* toggle 'solo' */
241         BKE_nlatrack_solo_toggle(adt, nlt);
242
243         /* notifier flags - channel was edited */
244         notifierFlags |= (ND_ANIMCHAN | NA_EDITED);
245         ale->update |= ANIM_UPDATE_DEPS;
246       }
247       else if (nlaedit_is_tweakmode_on(ac) == 0) {
248         /* set selection */
249         if (selectmode == SELECT_INVERT) {
250           /* inverse selection status of this F-Curve only */
251           nlt->flag ^= NLATRACK_SELECTED;
252         }
253         else {
254           /* select F-Curve by itself */
255           ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
256           nlt->flag |= NLATRACK_SELECTED;
257         }
258
259         /* if NLA-Track is selected now,
260          * make NLA-Track the 'active' one in the visible list */
261         if (nlt->flag & NLATRACK_SELECTED)
262           ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK);
263
264         /* notifier flags - channel was selected */
265         notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
266       }
267       break;
268     }
269     case ANIMTYPE_NLAACTION: {
270       AnimData *adt = BKE_animdata_from_id(ale->id);
271
272       /* button region... */
273       if (x >= (v2d->cur.xmax - NLACHANNEL_BUTTON_WIDTH)) {
274         if (nlaedit_is_tweakmode_on(ac) == 0) {
275           /* 'push-down' action - only usable when not in TweakMode */
276           /* TODO: make this use the operator instead of calling the function directly
277            * however, calling the operator requires that we supply the args,
278            * and that works with proper buttons only */
279           BKE_nla_action_pushdown(adt);
280         }
281         else {
282           /* when in tweakmode, this button becomes the toggle for mapped editing */
283           adt->flag ^= ADT_NLA_EDIT_NOMAP;
284         }
285
286         /* changes to NLA-Action occurred */
287         notifierFlags |= ND_NLA_ACTCHANGE;
288         ale->update |= ANIM_UPDATE_DEPS;
289       }
290       /* OR rest of name... */
291       else {
292         /* NOTE: rest of NLA-Action name doubles for operating on the AnimData block
293          * - this is useful when there's no clear divider, and makes more sense in
294          *   the case of users trying to use this to change actions
295          * - in tweakmode, clicking here gets us out of tweakmode, as changing selection
296          *   while in tweakmode is really evil!
297          * - we disable "solo" flags too, to make it easier to work with stashed actions
298          *   with less trouble
299          */
300         if (nlaedit_is_tweakmode_on(ac)) {
301           /* exit tweakmode immediately */
302           nlaedit_disable_tweakmode(ac, true);
303
304           /* changes to NLA-Action occurred */
305           notifierFlags |= ND_NLA_ACTCHANGE;
306           ale->update |= ANIM_UPDATE_DEPS;
307         }
308         else {
309           /* select/deselect */
310           if (selectmode == SELECT_INVERT) {
311             /* inverse selection status of this AnimData block only */
312             adt->flag ^= ADT_UI_SELECTED;
313           }
314           else {
315             /* select AnimData block by itself */
316             ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
317             adt->flag |= ADT_UI_SELECTED;
318           }
319
320           /* set active? */
321           if (adt->flag & ADT_UI_SELECTED)
322             adt->flag |= ADT_UI_ACTIVE;
323
324           notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
325         }
326       }
327       break;
328     }
329     default:
330       if (G.debug & G_DEBUG)
331         printf("Error: Invalid channel type in mouse_nla_channels()\n");
332       break;
333   }
334
335   /* free channels */
336   ANIM_animdata_update(ac, &anim_data);
337   ANIM_animdata_freelist(&anim_data);
338
339   /* return the notifier-flags set */
340   return notifierFlags;
341 }
342
343 /* ------------------- */
344
345 /* handle clicking */
346 static int nlachannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
347 {
348   bAnimContext ac;
349   SpaceNla *snla;
350   ARegion *ar;
351   View2D *v2d;
352   int channel_index;
353   int notifierFlags = 0;
354   short selectmode;
355   float x, y;
356
357   /* get editor data */
358   if (ANIM_animdata_get_context(C, &ac) == 0)
359     return OPERATOR_CANCELLED;
360
361   /* get useful pointers from animation context data */
362   snla = (SpaceNla *)ac.sl;
363   ar = ac.ar;
364   v2d = &ar->v2d;
365
366   /* select mode is either replace (deselect all, then add) or add/extend */
367   if (RNA_boolean_get(op->ptr, "extend"))
368     selectmode = SELECT_INVERT;
369   else
370     selectmode = SELECT_REPLACE;
371
372   /* figure out which channel user clicked in
373    * Note: although channels technically start at y= NLACHANNEL_FIRST, we need to adjust by half a channel's height
374    *      so that the tops of channels get caught ok. Since NLACHANNEL_FIRST is really NLACHANNEL_HEIGHT, we simply use
375    *      NLACHANNEL_HEIGHT_HALF.
376    */
377   UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y);
378   UI_view2d_listview_view_to_cell(v2d,
379                                   NLACHANNEL_NAMEWIDTH,
380                                   NLACHANNEL_STEP(snla),
381                                   0,
382                                   (float)NLACHANNEL_HEIGHT_HALF(snla),
383                                   x,
384                                   y,
385                                   NULL,
386                                   &channel_index);
387
388   /* handle mouse-click in the relevant channel then */
389   notifierFlags = mouse_nla_channels(C, &ac, x, channel_index, selectmode);
390
391   /* set notifier that things have changed */
392   WM_event_add_notifier(C, NC_ANIMATION | notifierFlags, NULL);
393
394   return OPERATOR_FINISHED;
395 }
396
397 void NLA_OT_channels_click(wmOperatorType *ot)
398 {
399   PropertyRNA *prop;
400
401   /* identifiers */
402   ot->name = "Mouse Click on NLA Channels";
403   ot->idname = "NLA_OT_channels_click";
404   ot->description = "Handle clicks to select NLA channels";
405
406   /* api callbacks */
407   ot->invoke = nlachannels_mouseclick_invoke;
408   ot->poll = ED_operator_nla_active;
409
410   /* flags */
411   ot->flag = OPTYPE_UNDO;
412
413   /* props */
414   prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");  // SHIFTKEY
415   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
416 }
417
418 /* *********************************************** */
419 /* Special Operators */
420
421 /* ******************** Action Push Down ******************************** */
422
423 static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
424 {
425   bAnimContext ac;
426   ID *id = NULL;
427   AnimData *adt = NULL;
428   int channel_index = RNA_int_get(op->ptr, "channel_index");
429
430   /* get editor data */
431   if (ANIM_animdata_get_context(C, &ac) == 0)
432     return OPERATOR_CANCELLED;
433
434   /* get anim-channel to use (or more specifically, the animdata block behind it) */
435   if (channel_index == -1) {
436     PointerRNA adt_ptr = {{NULL}};
437
438     /* active animdata block */
439     if (nla_panel_context(C, &adt_ptr, NULL, NULL) == 0 || (adt_ptr.data == NULL)) {
440       BKE_report(op->reports,
441                  RPT_ERROR,
442                  "No active AnimData block to use "
443                  "(select a data-block expander first or set the appropriate flags on an AnimData "
444                  "block)");
445       return OPERATOR_CANCELLED;
446     }
447     else {
448       id = adt_ptr.id.data;
449       adt = adt_ptr.data;
450     }
451   }
452   else {
453     /* indexed channel */
454     ListBase anim_data = {NULL, NULL};
455     bAnimListElem *ale;
456     int filter;
457
458     /* filter channels */
459     filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
460     ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
461
462     /* get channel from index */
463     ale = BLI_findlink(&anim_data, channel_index);
464     if (ale == NULL) {
465       BKE_reportf(op->reports, RPT_ERROR, "No animation channel found at index %d", channel_index);
466       ANIM_animdata_freelist(&anim_data);
467       return OPERATOR_CANCELLED;
468     }
469     else if (ale->type != ANIMTYPE_NLAACTION) {
470       BKE_reportf(op->reports,
471                   RPT_ERROR,
472                   "Animation channel at index %d is not a NLA 'Active Action' channel",
473                   channel_index);
474       ANIM_animdata_freelist(&anim_data);
475       return OPERATOR_CANCELLED;
476     }
477
478     /* grab AnimData from the channel */
479     adt = ale->adt;
480     id = ale->id;
481
482     /* we don't need anything here anymore, so free it all */
483     ANIM_animdata_freelist(&anim_data);
484   }
485
486   /* double-check that we are free to push down here... */
487   if (adt == NULL) {
488     BKE_report(op->reports, RPT_WARNING, "Internal Error - AnimData block is not valid");
489     return OPERATOR_CANCELLED;
490   }
491   else if (nlaedit_is_tweakmode_on(&ac)) {
492     BKE_report(op->reports,
493                RPT_WARNING,
494                "Cannot push down actions while tweaking a strip's action, exit tweak mode first");
495     return OPERATOR_CANCELLED;
496   }
497   else if (adt->action == NULL) {
498     BKE_report(op->reports, RPT_WARNING, "No active action to push down");
499     return OPERATOR_CANCELLED;
500   }
501   else {
502     /* 'push-down' action - only usable when not in TweakMode */
503     BKE_nla_action_pushdown(adt);
504
505     DEG_id_tag_update_ex(CTX_data_main(C), id, ID_RECALC_ANIMATION | ID_RECALC_COPY_ON_WRITE);
506   }
507
508   /* set notifier that things have changed */
509   WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
510   return OPERATOR_FINISHED;
511 }
512
513 void NLA_OT_action_pushdown(wmOperatorType *ot)
514 {
515   /* identifiers */
516   ot->name = "Push Down Action";
517   ot->idname = "NLA_OT_action_pushdown";
518   ot->description = "Push action down onto the top of the NLA stack as a new strip";
519
520   /* callbacks */
521   ot->exec = nlachannels_pushdown_exec;
522   ot->poll = nlaop_poll_tweakmode_off;
523
524   /* flags */
525   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
526
527   /* properties */
528   ot->prop = RNA_def_int(ot->srna,
529                          "channel_index",
530                          -1,
531                          -1,
532                          INT_MAX,
533                          "Channel Index",
534                          "Index of NLA action channel to perform pushdown operation on",
535                          0,
536                          INT_MAX);
537   RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE);
538 }
539
540 /* ******************** Action Unlink ******************************** */
541
542 static bool nla_action_unlink_poll(bContext *C)
543 {
544   if (ED_operator_nla_active(C)) {
545     return nla_panel_context(C, NULL, NULL, NULL);
546   }
547
548   /* something failed... */
549   return false;
550 }
551
552 static int nla_action_unlink_exec(bContext *C, wmOperator *op)
553 {
554   PointerRNA adt_ptr;
555   AnimData *adt;
556
557   /* check context and also validity of pointer */
558   if (!nla_panel_context(C, &adt_ptr, NULL, NULL))
559     return OPERATOR_CANCELLED;
560
561   /* get animdata */
562   adt = adt_ptr.data;
563   if (adt == NULL)
564     return OPERATOR_CANCELLED;
565
566   /* do unlinking */
567   if (adt && adt->action) {
568     bool force_delete = RNA_boolean_get(op->ptr, "force_delete");
569     ED_animedit_unlink_action(C, adt_ptr.id.data, adt, adt->action, op->reports, force_delete);
570   }
571
572   return OPERATOR_FINISHED;
573 }
574
575 static int nla_action_unlink_invoke(bContext *C, wmOperator *op, const wmEvent *evt)
576 {
577   /* NOTE: this is hardcoded to match the behavior for the unlink button
578    * (in interface_templates.c) */
579   RNA_boolean_set(op->ptr, "force_delete", evt->shift != 0);
580   return nla_action_unlink_exec(C, op);
581 }
582
583 void NLA_OT_action_unlink(wmOperatorType *ot)
584 {
585   PropertyRNA *prop;
586
587   /* identifiers */
588   ot->name = "Unlink Action";
589   ot->idname = "NLA_OT_action_unlink";
590   ot->description = "Unlink this action from the active action slot (and/or exit Tweak Mode)";
591
592   /* callbacks */
593   ot->invoke = nla_action_unlink_invoke;
594   ot->exec = nla_action_unlink_exec;
595   ot->poll = nla_action_unlink_poll;
596
597   /* properties */
598   prop = RNA_def_boolean(ot->srna,
599                          "force_delete",
600                          false,
601                          "Force Delete",
602                          "Clear Fake User and remove copy stashed in this datablock's NLA stack");
603   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
604 }
605
606 /* ******************** Add Tracks Operator ***************************** */
607 /* Add NLA Tracks to the same AnimData block as a selected track, or above the selected tracks */
608
609 /* helper - add NLA Tracks alongside existing ones */
610 bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel)
611 {
612   ListBase anim_data = {NULL, NULL};
613   bAnimListElem *ale;
614   int filter;
615   AnimData *lastAdt = NULL;
616   bool added = false;
617
618   /* get a list of the (selected) NLA Tracks being shown in the NLA */
619   filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL |
620             ANIMFILTER_NODUPLIS);
621   ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
622
623   /* add tracks... */
624   for (ale = anim_data.first; ale; ale = ale->next) {
625     if (ale->type == ANIMTYPE_NLATRACK) {
626       NlaTrack *nlt = (NlaTrack *)ale->data;
627       AnimData *adt = ale->adt;
628
629       /* check if just adding a new track above this one,
630        * or whether we're adding a new one to the top of the stack that this one belongs to
631        */
632       if (above_sel) {
633         /* just add a new one above this one */
634         BKE_nlatrack_add(adt, nlt);
635         ale->update = ANIM_UPDATE_DEPS;
636         added = true;
637       }
638       else if ((lastAdt == NULL) || (adt != lastAdt)) {
639         /* add one track to the top of the owning AnimData's stack,
640          * then don't add anymore to this stack */
641         BKE_nlatrack_add(adt, NULL);
642         lastAdt = adt;
643         ale->update = ANIM_UPDATE_DEPS;
644         added = true;
645       }
646     }
647   }
648
649   /* free temp data */
650   ANIM_animdata_update(ac, &anim_data);
651   ANIM_animdata_freelist(&anim_data);
652
653   return added;
654 }
655
656 /* helper - add NLA Tracks to empty (and selected) AnimData blocks */
657 bool nlaedit_add_tracks_empty(bAnimContext *ac)
658 {
659   ListBase anim_data = {NULL, NULL};
660   bAnimListElem *ale;
661   int filter;
662   bool added = false;
663
664   /* get a list of the selected AnimData blocks in the NLA */
665   filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA |
666             ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
667   ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
668
669   /* check if selected AnimData blocks are empty, and add tracks if so... */
670   for (ale = anim_data.first; ale; ale = ale->next) {
671     AnimData *adt = ale->adt;
672
673     /* sanity check */
674     BLI_assert(adt->flag & ADT_UI_SELECTED);
675
676     /* ensure it is empty */
677     if (BLI_listbase_is_empty(&adt->nla_tracks)) {
678       /* add new track to this AnimData block then */
679       BKE_nlatrack_add(adt, NULL);
680       ale->update = ANIM_UPDATE_DEPS;
681       added = true;
682     }
683   }
684
685   /* cleanup */
686   ANIM_animdata_update(ac, &anim_data);
687   ANIM_animdata_freelist(&anim_data);
688
689   return added;
690 }
691
692 /* ----- */
693
694 static int nlaedit_add_tracks_exec(bContext *C, wmOperator *op)
695 {
696   bAnimContext ac;
697   bool above_sel = RNA_boolean_get(op->ptr, "above_selected");
698   bool op_done = false;
699
700   /* get editor data */
701   if (ANIM_animdata_get_context(C, &ac) == 0)
702     return OPERATOR_CANCELLED;
703
704   /* perform adding in two passes - existing first so that we don't double up for empty */
705   op_done |= nlaedit_add_tracks_existing(&ac, above_sel);
706   op_done |= nlaedit_add_tracks_empty(&ac);
707
708   /* done? */
709   if (op_done) {
710     DEG_relations_tag_update(CTX_data_main(C));
711
712     /* set notifier that things have changed */
713     WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
714
715     /* done */
716     return OPERATOR_FINISHED;
717   }
718   else {
719     /* failed to add any tracks */
720     BKE_report(
721         op->reports, RPT_WARNING, "Select an existing NLA Track or an empty action line first");
722
723     /* not done */
724     return OPERATOR_CANCELLED;
725   }
726 }
727
728 void NLA_OT_tracks_add(wmOperatorType *ot)
729 {
730   /* identifiers */
731   ot->name = "Add Tracks";
732   ot->idname = "NLA_OT_tracks_add";
733   ot->description = "Add NLA-Tracks above/after the selected tracks";
734
735   /* api callbacks */
736   ot->exec = nlaedit_add_tracks_exec;
737   ot->poll = nlaop_poll_tweakmode_off;
738
739   /* flags */
740   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
741
742   /* properties */
743   RNA_def_boolean(ot->srna,
744                   "above_selected",
745                   0,
746                   "Above Selected",
747                   "Add a new NLA Track above every existing selected one");
748 }
749
750 /* ******************** Delete Tracks Operator ***************************** */
751 /* Delete selected NLA Tracks */
752
753 static int nlaedit_delete_tracks_exec(bContext *C, wmOperator *UNUSED(op))
754 {
755   bAnimContext ac;
756
757   ListBase anim_data = {NULL, NULL};
758   bAnimListElem *ale;
759   int filter;
760
761   /* get editor data */
762   if (ANIM_animdata_get_context(C, &ac) == 0)
763     return OPERATOR_CANCELLED;
764
765   /* get a list of the AnimData blocks being shown in the NLA */
766   filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL |
767             ANIMFILTER_NODUPLIS);
768   ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
769
770   /* delete tracks */
771   for (ale = anim_data.first; ale; ale = ale->next) {
772     if (ale->type == ANIMTYPE_NLATRACK) {
773       NlaTrack *nlt = (NlaTrack *)ale->data;
774       AnimData *adt = ale->adt;
775
776       /* if track is currently 'solo', then AnimData should have its
777        * 'has solo' flag disabled
778        */
779       if (nlt->flag & NLATRACK_SOLO)
780         adt->flag &= ~ADT_NLA_SOLO_TRACK;
781
782       /* call delete on this track - deletes all strips too */
783       BKE_nlatrack_free(&adt->nla_tracks, nlt, true);
784       ale->update = ANIM_UPDATE_DEPS;
785     }
786   }
787
788   /* free temp data */
789   ANIM_animdata_update(&ac, &anim_data);
790   ANIM_animdata_freelist(&anim_data);
791
792   DEG_relations_tag_update(ac.bmain);
793
794   /* set notifier that things have changed */
795   WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
796
797   /* done */
798   return OPERATOR_FINISHED;
799 }
800
801 void NLA_OT_tracks_delete(wmOperatorType *ot)
802 {
803   /* identifiers */
804   ot->name = "Delete Tracks";
805   ot->idname = "NLA_OT_tracks_delete";
806   ot->description = "Delete selected NLA-Tracks and the strips they contain";
807
808   /* api callbacks */
809   ot->exec = nlaedit_delete_tracks_exec;
810   ot->poll = nlaop_poll_tweakmode_off;
811
812   /* flags */
813   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
814 }
815
816 /* *********************************************** */
817 /* AnimData Related Operators */
818
819 /* ******************** Include Objects Operator ***************************** */
820 /* Include selected objects in NLA Editor, by giving them AnimData blocks
821  * NOTE: This doesn't help for non-object AnimData, where we do not have any effective
822  *       selection mechanism in place. Unfortunately, this means that non-object AnimData
823  *       once again becomes a second-class citizen here. However, at least for the most
824  *       common use case, we now have a nice shortcut again.
825  */
826
827 static int nlaedit_objects_add_exec(bContext *C, wmOperator *UNUSED(op))
828 {
829   bAnimContext ac;
830   SpaceNla *snla;
831
832   /* get editor data */
833   if (ANIM_animdata_get_context(C, &ac) == 0)
834     return OPERATOR_CANCELLED;
835
836   /* ensure that filters are set so that the effect will be immediately visible */
837   snla = (SpaceNla *)ac.sl;
838   if (snla && snla->ads) {
839     snla->ads->filterflag &= ~ADS_FILTER_NLA_NOACT;
840   }
841
842   /* operate on selected objects... */
843   CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
844     /* ensure that object has AnimData... that's all */
845     BKE_animdata_add_id(&ob->id);
846   }
847   CTX_DATA_END;
848
849   /* set notifier that things have changed */
850   WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
851
852   /* done */
853   return OPERATOR_FINISHED;
854 }
855
856 void NLA_OT_selected_objects_add(wmOperatorType *ot)
857 {
858   /* identifiers */
859   ot->name = "Include Selected Objects";
860   ot->idname = "NLA_OT_selected_objects_add";
861   ot->description = "Make selected objects appear in NLA Editor by adding Animation Data";
862
863   /* api callbacks */
864   ot->exec = nlaedit_objects_add_exec;
865   ot->poll = nlaop_poll_tweakmode_off;
866
867   /* flags */
868   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
869 }
870
871 /* *********************************************** */