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