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