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