Dopesheet: Keyframe size can be adjusted as part of theme settings
[blender.git] / source / blender / editors / space_action / action_data.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2015 Blender Foundation
19  * This is a new part of Blender
20  *
21  * Contributor(s): Joshua Leung
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/space_action/action_data.c
27  *  \ingroup spaction
28  */
29
30
31 #include <math.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <float.h>
35
36
37 #include "BLI_blenlib.h"
38 #include "BLI_math.h"
39 #include "BLI_utildefines.h"
40
41 #include "BLT_translation.h"
42
43 #include "DNA_anim_types.h"
44 #include "DNA_gpencil_types.h"
45 #include "DNA_key_types.h"
46 #include "DNA_object_types.h"
47 #include "DNA_scene_types.h"
48 #include "DNA_mask_types.h"
49
50 #include "RNA_access.h"
51 #include "RNA_define.h"
52 #include "RNA_enum_types.h"
53
54 #include "BKE_animsys.h"
55 #include "BKE_action.h"
56 #include "BKE_fcurve.h"
57 #include "BKE_global.h"
58 #include "BKE_library.h"
59 #include "BKE_key.h"
60 #include "BKE_main.h"
61 #include "BKE_nla.h"
62 #include "BKE_scene.h"
63 #include "BKE_context.h"
64 #include "BKE_report.h"
65
66 #include "UI_view2d.h"
67
68 #include "ED_anim_api.h"
69 #include "ED_gpencil.h"
70 #include "ED_keyframing.h"
71 #include "ED_keyframes_edit.h"
72 #include "ED_screen.h"
73 #include "ED_markers.h"
74 #include "ED_mask.h"
75
76 #include "WM_api.h"
77 #include "WM_types.h"
78
79 #include "UI_interface.h"
80
81 #include "action_intern.h"
82
83 /* ************************************************************************** */
84 /* ACTION CREATION */
85
86 /* Helper function to find the active AnimData block from the Action Editor context */
87 AnimData *ED_actedit_animdata_from_context(bContext *C)
88 {
89         SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
90         Object *ob = CTX_data_active_object(C);
91         AnimData *adt = NULL;
92         
93         /* Get AnimData block to use */
94         if (saction->mode == SACTCONT_ACTION) {
95                 /* Currently, "Action Editor" means object-level only... */
96                 if (ob) {
97                         adt = ob->adt;
98                 }
99         }
100         else if (saction->mode == SACTCONT_SHAPEKEY) {
101                 Key *key = BKE_key_from_object(ob);
102                 if (key) {
103                         adt = key->adt;
104                 }
105         }
106         
107         return adt;
108 }
109
110 /* -------------------------------------------------------------------- */
111
112 /* Create new action */
113 static bAction *action_create_new(bContext *C, bAction *oldact)
114 {
115         ScrArea *sa = CTX_wm_area(C);
116         bAction *action;
117         
118         /* create action - the way to do this depends on whether we've got an
119          * existing one there already, in which case we make a copy of it
120          * (which is useful for "versioning" actions within the same file)
121          */
122         if (oldact && GS(oldact->id.name) == ID_AC) {
123                 /* make a copy of the existing action */
124                 action = BKE_action_copy(oldact);
125         }
126         else {
127                 /* just make a new (empty) action */
128                 action = add_empty_action(CTX_data_main(C), "Action");
129         }
130         
131         /* when creating new ID blocks, there is already 1 user (as for all new datablocks), 
132          * but the RNA pointer code will assign all the proper users instead, so we compensate
133          * for that here
134          */
135         BLI_assert(action->id.us == 1);
136         id_us_min(&action->id);
137         
138         /* set ID-Root type */
139         if (sa->spacetype == SPACE_ACTION) {
140                 SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
141                 
142                 if (saction->mode == SACTCONT_SHAPEKEY)
143                         action->idroot = ID_KE;
144                 else
145                         action->idroot = ID_OB;
146         }
147         
148         return action;
149 }
150
151 /* Change the active action used by the action editor */
152 static void actedit_change_action(bContext *C, bAction *act)
153 {
154         bScreen *screen = CTX_wm_screen(C);
155         SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
156         
157         PointerRNA ptr, idptr;
158         PropertyRNA *prop;
159         
160         /* create RNA pointers and get the property */
161         RNA_pointer_create(&screen->id, &RNA_SpaceDopeSheetEditor, saction, &ptr);
162         prop = RNA_struct_find_property(&ptr, "action");
163         
164         /* NOTE: act may be NULL here, so better to just use a cast here */
165         RNA_id_pointer_create((ID *)act, &idptr);
166         
167         /* set the new pointer, and force a refresh */
168         RNA_property_pointer_set(&ptr, prop, idptr);
169         RNA_property_update(C, &ptr, prop);
170 }
171
172 /* ******************** New Action Operator *********************** */
173
174 /* Criteria:
175  *  1) There must be an dopesheet/action editor, and it must be in a mode which uses actions...
176  *        OR
177  *     The NLA Editor is active (i.e. Animation Data panel -> new action)
178  *  2) The associated AnimData block must not be in tweakmode
179  */
180 static int action_new_poll(bContext *C)
181 {
182         Scene *scene = CTX_data_scene(C);
183         
184         /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */
185         /* NOTE: unlike for pushdown, this operator needs to be run when creating an action from nothing... */  
186         if (ED_operator_action_active(C)) {
187                 SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
188                 Object *ob = CTX_data_active_object(C);
189                 
190                 /* For now, actions are only for the active object, and on object and shapekey levels... */
191                 if (saction->mode == SACTCONT_ACTION) {
192                         /* XXX: This assumes that actions are assigned to the active object in this mode */
193                         if (ob) {
194                                 if ((ob->adt == NULL) || (ob->adt->flag & ADT_NLA_EDIT_ON) == 0)
195                                         return true;
196                         }
197                 }
198                 else if (saction->mode == SACTCONT_SHAPEKEY) {
199                         Key *key = BKE_key_from_object(ob);
200                         if (key) {
201                                 if ((key->adt == NULL) || (key->adt->flag & ADT_NLA_EDIT_ON) == 0)
202                                         return true;
203                         }
204                 }
205         }
206         else if (ED_operator_nla_active(C)) {
207                 if (!(scene->flag & SCE_NLA_EDIT_ON)) {
208                         return true;
209                 }
210         }
211         
212         /* something failed... */
213         return false;
214 }
215
216 static int action_new_exec(bContext *C, wmOperator *UNUSED(op))
217 {
218         PointerRNA ptr, idptr;
219         PropertyRNA *prop;
220         
221         /* hook into UI */
222         UI_context_active_but_prop_get_templateID(C, &ptr, &prop);
223         
224         if (prop) {
225                 bAction *action = NULL, *oldact = NULL;
226                 AnimData *adt = NULL;
227                 PointerRNA oldptr;
228                 
229                 oldptr = RNA_property_pointer_get(&ptr, prop);
230                 oldact = (bAction *)oldptr.id.data;
231                 
232                 /* stash the old action to prevent it from being lost */
233                 if (ptr.type == &RNA_AnimData) {
234                         adt = ptr.data;
235                 }
236                 else if (ptr.type == &RNA_SpaceDopeSheetEditor) {
237                         adt = ED_actedit_animdata_from_context(C);
238                 }
239                 
240                 /* Perform stashing operation - But only if there is an action */
241                 if (adt && oldact) {
242                         /* stash the action */
243                         if (BKE_nla_action_stash(adt)) {
244                                 /* The stash operation will remove the user already
245                                  * (and unlink the action from the AnimData action slot).
246                                  * Hence, we must unset the ref to the action in the
247                                  * action editor too (if this is where we're being called from)
248                                  * first before setting the new action once it is created,
249                                  * or else the user gets decremented twice!
250                                  */
251                                 if (ptr.type == &RNA_SpaceDopeSheetEditor) {
252                                         SpaceAction *saction = (SpaceAction *)ptr.data;
253                                         saction->action = NULL;
254                                 }
255                         }
256                         else {
257                                 //printf("WARNING: Failed to stash %s. It may already exist in the NLA stack though\n", oldact->id.name);
258                         }
259                 }
260                 
261                 /* create action */
262                 action = action_create_new(C, oldact);
263                 
264                 /* set this new action
265                  * NOTE: we can't use actedit_change_action, as this function is also called from the NLA
266                  */
267                 RNA_id_pointer_create(&action->id, &idptr);
268                 RNA_property_pointer_set(&ptr, prop, idptr);
269                 RNA_property_update(C, &ptr, prop);
270         }
271         
272         /* set notifier that keyframes have changed */
273         WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
274         
275         return OPERATOR_FINISHED;
276 }
277  
278 void ACTION_OT_new(wmOperatorType *ot)
279 {
280         /* identifiers */
281         ot->name = "New Action";
282         ot->idname = "ACTION_OT_new";
283         ot->description = "Create new action";
284         
285         /* api callbacks */
286         ot->exec = action_new_exec;
287         ot->poll = action_new_poll;
288         
289         /* flags */
290         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
291 }
292
293 /* ******************* Action Push-Down Operator ******************** */
294
295 /* Criteria:
296  *  1) There must be an dopesheet/action editor, and it must be in a mode which uses actions 
297  *  2) There must be an action active
298  *  3) The associated AnimData block must not be in tweakmode
299  */
300 static int action_pushdown_poll(bContext *C)
301 {
302         if (ED_operator_action_active(C)) {
303                 SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
304                 AnimData *adt = ED_actedit_animdata_from_context(C);
305                 
306                 /* Check for AnimData, Actions, and that tweakmode is off */
307                 if (adt && saction->action) {
308                         /* NOTE: We check this for the AnimData block in question and not the global flag,
309                          *       as the global flag may be left dirty by some of the browsing ops here.
310                          */
311                         if (!(adt->flag & ADT_NLA_EDIT_ON))
312                                 return true;
313                 }
314         }
315         
316         /* something failed... */
317         return false;
318 }
319
320 static int action_pushdown_exec(bContext *C, wmOperator *op)
321 {
322         SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
323         AnimData *adt = ED_actedit_animdata_from_context(C);
324         
325         /* Do the deed... */
326         if (adt) {
327                 /* Perform the pushdown operation
328                  * - This will deal with all the AnimData-side usercounts
329                  */
330                 if (action_has_motion(adt->action) == 0) {
331                         /* action may not be suitable... */
332                         BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
333                         return OPERATOR_CANCELLED;
334                 }
335                 else {
336                         /* action can be safely added */
337                         BKE_nla_action_pushdown(adt);
338                 }
339                 
340                 /* Stop displaying this action in this editor
341                  * NOTE: The editor itself doesn't set a user...
342                  */
343                 saction->action = NULL;
344         }
345         
346         /* Send notifiers that stuff has changed */
347         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
348         return OPERATOR_FINISHED;
349 }
350
351 void ACTION_OT_push_down(wmOperatorType *ot)
352 {
353         /* identifiers */
354         ot->name = "Push Down Action";
355         ot->idname = "ACTION_OT_push_down";
356         ot->description = "Push action down on to the NLA stack as a new strip";
357         
358         /* callbacks */
359         ot->exec = action_pushdown_exec;
360         ot->poll = action_pushdown_poll;
361         
362         /* flags */
363         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
364 }
365
366 /* ******************* Action Stash Operator ******************** */
367
368 static int action_stash_exec(bContext *C, wmOperator *op)
369 {
370         SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
371         AnimData *adt = ED_actedit_animdata_from_context(C);
372         
373         /* Perform stashing operation */
374         if (adt) {
375                 /* don't do anything if this action is empty... */
376                 if (action_has_motion(adt->action) == 0) {
377                         /* action may not be suitable... */
378                         BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
379                         return OPERATOR_CANCELLED;
380                 }
381                 else {
382                         /* stash the action */
383                         if (BKE_nla_action_stash(adt)) {
384                                 /* The stash operation will remove the user already,
385                                  * so the flushing step later shouldn't double up
386                                  * the usercount fixes. Hence, we must unset this ref
387                                  * first before setting the new action.
388                                  */
389                                 saction->action = NULL;
390                         }
391                         else {
392                                 /* action has already been added - simply warn about this, and clear */
393                                 BKE_report(op->reports, RPT_ERROR, "Action has already been stashed");
394                         }
395                         
396                         /* clear action refs from editor, and then also the backing data (not necessary) */
397                         actedit_change_action(C, NULL);
398                 }
399         }
400         
401         /* Send notifiers that stuff has changed */
402         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
403         return OPERATOR_FINISHED;
404 }
405
406 void ACTION_OT_stash(wmOperatorType *ot)
407 {
408         /* identifiers */
409         ot->name = "Stash Action";
410         ot->idname = "ACTION_OT_stash";
411         ot->description = "Store this action in the NLA stack as a non-contributing strip for later use";
412         
413         /* callbacks */
414         ot->exec = action_stash_exec;
415         ot->poll = action_pushdown_poll;
416         
417         /* flags */
418         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
419         
420         /* properties */
421         ot->prop = RNA_def_boolean(ot->srna, "create_new", true, "Create New Action", 
422                                    "Create a new action once the existing one has been safely stored");
423 }
424
425 /* ----------------- */
426
427 /* Criteria:
428  *  1) There must be an dopesheet/action editor, and it must be in a mode which uses actions 
429  *  2) The associated AnimData block must not be in tweakmode
430  */
431 static int action_stash_create_poll(bContext *C)
432 {
433         if (ED_operator_action_active(C)) {
434                 AnimData *adt = ED_actedit_animdata_from_context(C);
435                 
436                 /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */
437                 /* NOTE: unlike for pushdown, this operator needs to be run when creating an action from nothing... */
438                 if (adt) {
439                         if (!(adt->flag & ADT_NLA_EDIT_ON))
440                                 return true;
441                 }
442                 else {
443                         /* There may not be any action/animdata yet, so, just fallback to the global setting
444                          * (which may not be totally valid yet if the action editor was used and things are 
445                          * now in an inconsistent state)
446                          */
447                         SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
448                         Scene *scene = CTX_data_scene(C);
449                         
450                         if (!(scene->flag & SCE_NLA_EDIT_ON)) {
451                                 /* For now, actions are only for the active object, and on object and shapekey levels... */
452                                 return ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY);
453                         }
454                 }
455         }
456         
457         /* something failed... */
458         return false;
459 }
460
461 static int action_stash_create_exec(bContext *C, wmOperator *op)
462 {
463         SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
464         AnimData *adt = ED_actedit_animdata_from_context(C);
465         
466         /* Check for no action... */
467         if (saction->action == NULL) {
468                 /* just create a new action */
469                 bAction *action = action_create_new(C, NULL);
470                 actedit_change_action(C, action);
471         }
472         else if (adt) {
473                 /* Perform stashing operation */
474                 if (action_has_motion(adt->action) == 0) {
475                         /* don't do anything if this action is empty... */
476                         BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier");
477                         return OPERATOR_CANCELLED;
478                 }
479                 else {
480                         /* stash the action */
481                         if (BKE_nla_action_stash(adt)) {
482                                 bAction *new_action = NULL;
483                                 
484                                 /* create new action not based on the old one (since the "new" operator already does that) */
485                                 new_action = action_create_new(C, NULL);
486                                 
487                                 /* The stash operation will remove the user already,
488                                  * so the flushing step later shouldn't double up
489                                  * the usercount fixes. Hence, we must unset this ref
490                                  * first before setting the new action.
491                                  */
492                                 saction->action = NULL;
493                                 actedit_change_action(C, new_action);
494                         }
495                         else {
496                                 /* action has already been added - simply warn about this, and clear */
497                                 BKE_report(op->reports, RPT_ERROR, "Action has already been stashed");
498                                 actedit_change_action(C, NULL);
499                         }
500                 }
501         }
502         
503         /* Send notifiers that stuff has changed */
504         WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
505         return OPERATOR_FINISHED;
506 }
507
508 void ACTION_OT_stash_and_create(wmOperatorType *ot)
509 {
510         /* identifiers */
511         ot->name = "Stash Action";
512         ot->idname = "ACTION_OT_stash_and_create";
513         ot->description = "Store this action in the NLA stack as a non-contributing strip for later use, and create a new action";
514         
515         /* callbacks */
516         ot->exec = action_stash_create_exec;
517         ot->poll = action_stash_create_poll;
518         
519         /* flags */
520         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
521 }
522
523 /* ************************************************************************** */
524 /* ACTION UNLINK */
525
526 /* ******************* Action Unlink Operator ******************** */
527 /* We use a custom unlink operator here, as there are some technicalities which need special care:
528  * 1) When in Tweak Mode, it shouldn't be possible to unlink the active action,
529  *    or else, everything turns to custard.
530  * 2) If the Action doesn't have any other users, the user should at least get
531  *    a warning that it is going to get lost.
532  * 3) We need a convenient way to exit Tweak Mode from the Action Editor
533  */
534
535 void ED_animedit_unlink_action(bContext *C, ID *id, AnimData *adt, bAction *act, ReportList *reports, bool force_delete)
536 {
537         ScrArea *sa = CTX_wm_area(C);
538         
539         /* If the old action only has a single user (that it's about to lose),
540          * warn user about it
541          *
542          * TODO: Maybe we should just save it for them? But then, there's the problem of
543          *       trying to get rid of stuff that's actually unwanted!
544          */
545         if (act->id.us == 1) {
546                 BKE_reportf(reports, RPT_WARNING,
547                             "Action '%s' will not be saved, create Fake User or Stash in NLA Stack to retain",
548                             act->id.name + 2);
549         }
550         
551         /* Clear Fake User and remove action stashing strip (if present) */
552         if (force_delete) {
553                 /* Remove stashed strip binding this action to this datablock */
554                 /* XXX: we cannot unlink it from *OTHER* datablocks that may also be stashing it,
555                  * but GE users only seem to use/care about single-object binding for now so this
556                  * should be fine
557                  */
558                 if (adt) {
559                         NlaTrack *nlt, *nlt_next;
560                         NlaStrip *strip, *nstrip;
561                         
562                         for (nlt = adt->nla_tracks.first; nlt; nlt = nlt_next) {
563                                 nlt_next = nlt->next;
564                                 
565                                 if (strstr(nlt->name, DATA_("[Action Stash]"))) {
566                                         for (strip = nlt->strips.first; strip; strip = nstrip) {
567                                                 nstrip = strip->next;
568                                                 
569                                                 if (strip->act == act) {
570                                                         /* Remove this strip, and the track too if it doesn't have anything else */
571                                                         free_nlastrip(&nlt->strips, strip);
572                                                         
573                                                         if (nlt->strips.first == NULL) {
574                                                                 BLI_assert(nstrip == NULL);
575                                                                 free_nlatrack(&adt->nla_tracks, nlt);
576                                                         }
577                                                 }
578                                         }
579                                 }
580                         }
581                 }
582                 
583                 /* Clear Fake User */
584                 id_fake_user_clear(&act->id);
585         }
586         
587         /* If in Tweak Mode, don't unlink. Instead, this 
588          * becomes a shortcut to exit Tweak Mode instead
589          */
590         if ((adt) && (adt->flag & ADT_NLA_EDIT_ON)) {
591                 /* Exit Tweak Mode */
592                 BKE_nla_tweakmode_exit(adt);
593                 
594                 /* Flush this to the Action Editor (if that's where this change was initiated) */
595                 if (sa->spacetype == SPACE_ACTION) {
596                         actedit_change_action(C, NULL);
597                 }
598         }
599         else {
600                 /* Unlink normally - Setting it to NULL should be enough to get the old one unlinked */
601                 if (sa->spacetype == SPACE_ACTION) {
602                         /* clear action editor -> action */
603                         actedit_change_action(C, NULL);
604                 }
605                 else {
606                         /* clear AnimData -> action */
607                         PointerRNA ptr;
608                         PropertyRNA *prop;
609                         
610                         /* create AnimData RNA pointers */
611                         RNA_pointer_create(id, &RNA_AnimData, adt, &ptr);
612                         prop = RNA_struct_find_property(&ptr, "action");
613                         
614                         /* clear... */
615                         RNA_property_pointer_set(&ptr, prop, PointerRNA_NULL);
616                         RNA_property_update(C, &ptr, prop);
617                 }
618         }
619 }
620
621 /* -------------------------- */
622
623 static int action_unlink_poll(bContext *C)
624 {
625         if (ED_operator_action_active(C)) {
626                 SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
627                 AnimData *adt = ED_actedit_animdata_from_context(C);
628                 
629                 /* Only when there's an active action, in the right modes... */
630                 if (saction->action && adt)
631                         return true;
632         }
633         
634         /* something failed... */
635         return false;
636 }
637
638 static int action_unlink_exec(bContext *C, wmOperator *op)
639 {
640         AnimData *adt = ED_actedit_animdata_from_context(C);
641         bool force_delete = RNA_boolean_get(op->ptr, "force_delete");
642         
643         if (adt && adt->action) {
644                 ED_animedit_unlink_action(C, NULL, adt, adt->action, op->reports, force_delete);
645         }
646         
647         return OPERATOR_FINISHED;
648 }
649
650 static int action_unlink_invoke(bContext *C, wmOperator *op, const wmEvent *evt)
651 {
652         /* NOTE: this is hardcoded to match the behaviour for the unlink button (in interface_templates.c) */
653         RNA_boolean_set(op->ptr, "force_delete", evt->shift != 0);
654         return action_unlink_exec(C, op);
655 }
656
657 void ACTION_OT_unlink(wmOperatorType *ot)
658 {
659         PropertyRNA *prop;
660         
661         /* identifiers */
662         ot->name = "Unlink Action";
663         ot->idname = "ACTION_OT_unlink";
664         ot->description = "Unlink this action from the active action slot (and/or exit Tweak Mode)";
665         
666         /* callbacks */
667         ot->invoke = action_unlink_invoke;
668         ot->exec = action_unlink_exec;
669         ot->poll = action_unlink_poll;
670         
671         /* properties */
672         prop = RNA_def_boolean(ot->srna, "force_delete", false, "Force Delete", 
673                                "Clear Fake User and remove copy stashed in this datablock's NLA stack");
674         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
675 }
676
677 /* ************************************************************************** */
678 /* ACTION BROWSING */
679
680 /* Try to find NLA Strip to use for action layer up/down tool */
681 static NlaStrip *action_layer_get_nlastrip(ListBase *strips, float ctime)
682 {
683         NlaStrip *strip;
684         
685         for (strip = strips->first; strip; strip = strip->next) {
686                 /* Can we use this? */
687                 if (IN_RANGE_INCL(ctime, strip->start, strip->end)) {
688                         /* in range - use this one */
689                         return strip;
690                 }
691                 else if ((ctime < strip->start) && (strip->prev == NULL)) {
692                         /* before first - use this one */
693                         return strip;
694                 }
695                 else if ((ctime > strip->end) && (strip->next == NULL)) {
696                         /* after last - use this one */
697                         return strip;
698                 }
699         }
700         
701         /* nothing suitable found... */
702         return NULL;
703 }
704
705 /* Switch NLA Strips/Actions  */
706 static void action_layer_switch_strip(AnimData *adt,
707                                       NlaTrack *old_track, NlaStrip *old_strip,
708                                       NlaTrack *nlt, NlaStrip *strip)
709 {
710         /* Exit tweakmode on old strip
711          * NOTE: We need to manually clear this stuff ourselves, as tweakmode exit doesn't do it
712          */
713         BKE_nla_tweakmode_exit(adt);
714         
715         if (old_strip) {
716                 old_strip->flag &= ~(NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT);
717         }
718         if (old_track) {
719                 old_track->flag &= ~(NLATRACK_ACTIVE | NLATRACK_SELECTED);
720         }
721         
722         /* Make this one the active one instead */
723         strip->flag |= (NLASTRIP_FLAG_ACTIVE | NLASTRIP_FLAG_SELECT);
724         nlt->flag |= NLATRACK_ACTIVE;
725         
726         /* Copy over "solo" flag - This is useful for stashed actions... */
727         if (old_track) {
728                 if (old_track->flag & NLATRACK_SOLO) {
729                         old_track->flag &= ~NLATRACK_SOLO;
730                         nlt->flag |= NLATRACK_SOLO;
731                 }
732         }
733         else {
734                 /* NLA muting <==> Solo Tracks */
735                 if (adt->flag & ADT_NLA_EVAL_OFF) {
736                         /* disable NLA muting */
737                         adt->flag &= ~ADT_NLA_EVAL_OFF;
738                         
739                         /* mark this track as being solo */
740                         adt->flag |= ADT_NLA_SOLO_TRACK;
741                         nlt->flag |= NLATRACK_SOLO;
742                         
743                         // TODO: Needs restpose flushing (when we get reference track)
744                 }
745         }
746         
747         /* Enter tweakmode again - hopefully we're now "it" */
748         BKE_nla_tweakmode_enter(adt);
749         BLI_assert(adt->actstrip == strip);
750 }
751
752 /* ********************** One Layer Up Operator ************************** */
753
754 static int action_layer_next_poll(bContext *C)
755 {
756         /* Action Editor's action editing modes only */
757         if (ED_operator_action_active(C)) {
758                 AnimData *adt = ED_actedit_animdata_from_context(C);
759                 if (adt) {
760                         /* only allow if we're in tweakmode, and there's something above us... */
761                         if (adt->flag & ADT_NLA_EDIT_ON) {
762                                 /* We need to check if there are any tracks above the active one
763                                  * since the track the action comes from is not stored in AnimData
764                                  */
765                                 if (adt->nla_tracks.last) {
766                                         NlaTrack *nlt = (NlaTrack *)adt->nla_tracks.last;
767                                         
768                                         if (nlt->flag & NLATRACK_DISABLED) {
769                                                 /* A disabled track will either be the track itself,
770                                                  * or one of the ones above it.
771                                                  *
772                                                  * If this is the top-most one, there is the possibility
773                                                  * that there is no active action. For now, we let this
774                                                  * case return true too, so that there is a natural way
775                                                  * to "move to an empty layer", even though this means
776                                                  * that we won't actually have an action.
777                                                  */
778                                                 // return (adt->tmpact != NULL);
779                                                 return true;
780                                         }
781                                 }
782                         }
783                 }
784         }
785         
786         /* something failed... */
787         return false;
788 }
789
790 static int action_layer_next_exec(bContext *C, wmOperator *op)
791 {
792         AnimData *adt = ED_actedit_animdata_from_context(C);
793         NlaTrack *act_track;
794         
795         Scene *scene = CTX_data_scene(C);
796         float ctime = BKE_scene_frame_get(scene);
797         
798         /* Get active track */
799         act_track = BKE_nlatrack_find_tweaked(adt);
800         
801         if (act_track == NULL) {
802                 BKE_report(op->reports, RPT_ERROR, "Could not find current NLA Track");
803                 return OPERATOR_CANCELLED;
804         }
805         
806         /* Find next action, and hook it up */
807         if (act_track->next) {
808                 NlaTrack *nlt;
809                 
810                 /* Find next action to use */
811                 for (nlt = act_track->next; nlt; nlt = nlt->next) {
812                         NlaStrip *strip = action_layer_get_nlastrip(&nlt->strips, ctime);
813                         
814                         if (strip) {
815                                 action_layer_switch_strip(adt, act_track, adt->actstrip, nlt, strip);
816                                 break;
817                         }
818                 }
819         }
820         else {
821                 /* No more actions (strips) - Go back to editing the original active action
822                  * NOTE: This will mean exiting tweakmode...
823                  */
824                 BKE_nla_tweakmode_exit(adt);
825                 
826                 /* Deal with solo flags...
827                  * Assume: Solo Track == NLA Muting
828                  */
829                 if (adt->flag & ADT_NLA_SOLO_TRACK) {
830                         /* turn off solo flags on tracks */
831                         act_track->flag &= ~NLATRACK_SOLO;
832                         adt->flag &= ~ADT_NLA_SOLO_TRACK;
833                         
834                         /* turn on NLA muting (to keep same effect) */
835                         adt->flag |= ADT_NLA_EVAL_OFF;
836                         
837                         // TODO: Needs restpose flushing (when we get reference track)
838                 }
839         }
840         
841         /* Update the action that this editor now uses
842          * NOTE: The calls above have already handled the usercount/animdata side of things
843          */
844         actedit_change_action(C, adt->action);
845         return OPERATOR_FINISHED;
846 }
847
848 void ACTION_OT_layer_next(wmOperatorType *ot)
849 {
850         /* identifiers */
851         ot->name = "Next Layer";
852         ot->idname = "ACTION_OT_layer_next";
853         ot->description = "Switch to editing action in animation layer above the current action in the NLA Stack";
854         
855         /* callbacks */
856         ot->exec = action_layer_next_exec;
857         ot->poll = action_layer_next_poll;
858         
859         /* flags */
860         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
861 }
862
863 /* ********************* One Layer Down Operator ************************* */
864
865 static int action_layer_prev_poll(bContext *C)
866 {
867         /* Action Editor's action editing modes only */
868         if (ED_operator_action_active(C)) {
869                 AnimData *adt = ED_actedit_animdata_from_context(C);
870                 if (adt) {
871                         if (adt->flag & ADT_NLA_EDIT_ON) {
872                                 /* Tweak Mode: We need to check if there are any tracks below the active one that we can move to */
873                                 if (adt->nla_tracks.first) {
874                                         NlaTrack *nlt = (NlaTrack *)adt->nla_tracks.first;
875                                         
876                                         /* Since the first disabled track is the track being tweaked/edited,
877                                          * we can simplify things by only checking the first track:
878                                          *    - If it is disabled, this is the track being tweaked,
879                                          *      so there can't be anything below it
880                                          *    - Otherwise, there is at least 1 track below the tweaking
881                                          *      track that we can descend to
882                                          */
883                                         if ((nlt->flag & NLATRACK_DISABLED) == 0) {
884                                                 /* not disabled = there are actions below the one being tweaked */
885                                                 return true;
886                                         }
887                                 }
888                         }
889                         else {
890                                 /* Normal Mode: If there are any tracks, we can try moving to those */
891                                 return (adt->nla_tracks.first != NULL);
892                         }
893                 }
894         }
895         
896         /* something failed... */
897         return false;
898 }
899
900 static int action_layer_prev_exec(bContext *C, wmOperator *op)
901 {
902         AnimData *adt = ED_actedit_animdata_from_context(C);
903         NlaTrack *act_track;
904         NlaTrack *nlt;
905         
906         Scene *scene = CTX_data_scene(C);
907         float ctime = BKE_scene_frame_get(scene);
908         
909         /* Sanity Check */
910         if (adt == NULL) {
911                 BKE_report(op->reports, RPT_ERROR, "Internal Error: Could not find Animation Data/NLA Stack to use");
912                 return OPERATOR_CANCELLED;
913         }
914         
915         /* Get active track */
916         act_track = BKE_nlatrack_find_tweaked(adt);
917         
918         /* If there is no active track, that means we are using the active action... */
919         if (act_track) {
920                 /* Active Track - Start from the one below it */
921                 nlt = act_track->prev;
922         }
923         else {
924                 /* Active Action - Use the top-most track */
925                 nlt = adt->nla_tracks.last;
926         }
927         
928         /* Find previous action and hook it up */
929         for (; nlt; nlt = nlt->prev) {
930                 NlaStrip *strip = action_layer_get_nlastrip(&nlt->strips, ctime);
931                 
932                 if (strip) {
933                         action_layer_switch_strip(adt, act_track, adt->actstrip, nlt, strip);
934                         break;
935                 }
936         }
937         
938         /* Update the action that this editor now uses
939          * NOTE: The calls above have already handled the usercount/animdata side of things
940          */
941         actedit_change_action(C, adt->action);
942         return OPERATOR_FINISHED;
943 }
944
945 void ACTION_OT_layer_prev(wmOperatorType *ot)
946 {
947         /* identifiers */
948         ot->name = "Previous Layer";
949         ot->idname = "ACTION_OT_layer_prev";
950         ot->description = "Switch to editing action in animation layer below the current action in the NLA Stack";
951         
952         /* callbacks */
953         ot->exec = action_layer_prev_exec;
954         ot->poll = action_layer_prev_poll;
955         
956         /* flags */
957         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
958 }
959
960 /* ************************************************************************** */