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