Action Editor WIP: Adding new actions in Action Editor now uses the "stash and create...
authorJoshua Leung <aligorith@gmail.com>
Sat, 28 Feb 2015 11:38:44 +0000 (00:38 +1300)
committerJoshua Leung <aligorith@gmail.com>
Sat, 28 Feb 2015 13:34:51 +0000 (02:34 +1300)
In constrast to the old "new" operator, this operator will stash the existing action
in the stack to prevent it from being lost. This situation isn't totally ideal yet,
since the NLA Editor still calls the old method.

release/scripts/startup/bl_ui/space_dopesheet.py
source/blender/editors/space_action/action_edit.c
source/blender/editors/space_action/action_intern.h
source/blender/editors/space_action/action_ops.c

index 5358670c2f234b50367b4b5e1a306a13b4ff5a67..67849a99abe69a7de629f35a834f5ac29ed6bbc8 100644 (file)
@@ -122,7 +122,7 @@ class DOPESHEET_HT_header(Header):
             dopesheet_filter(layout, context, genericFiltersOnly=True)
 
         if st.mode in {'ACTION', 'SHAPEKEY'}:
-            layout.template_ID(st, "action", new="action.new")
+            layout.template_ID(st, "action", new="action.stash_and_create")
 
             row = layout.row(align=True)
             row.operator("action.push_down", text="Push Down", icon='NLA_PUSHDOWN')
index ba06c7cf0e2e1e2f4357f4337509f5af6ea696ed..0e96c90f1391b17a8911c68dd778924c57494980 100644 (file)
@@ -206,7 +206,6 @@ void ACTION_OT_new(wmOperatorType *ot)
        
        /* api callbacks */
        ot->exec = action_new_exec;
-       // TODO: add a new invoke() callback to catch cases where users unexpectedly delete their data
        
        /* NOTE: this is used in the NLA too... */
        //ot->poll = ED_operator_action_active;
@@ -311,27 +310,20 @@ static int action_stash_exec(bContext *C, wmOperator *op)
                else {
                        /* stash the action */
                        if (BKE_nla_action_stash(adt)) {
-                               bAction *new_action = NULL;
-                               
-                               /* create new action (if required) */
-                               // XXX: maybe this should be a separate operator?
-                               if (RNA_boolean_get(op->ptr, "create_new")) {
-                                       new_action = action_create_new(C, saction->action);
-                               }
-                               
                                /* The stash operation will remove the user already,
                                 * so the flushing step later shouldn't double up
                                 * the usercount fixes. Hence, we must unset this ref
                                 * first before setting the new action.
                                 */
                                saction->action = NULL;
-                               actedit_change_action(C, new_action);
                        }
                        else {
                                /* action has already been added - simply warn about this, and clear */
                                BKE_report(op->reports, RPT_ERROR, "Action has already been stashed");
-                               actedit_change_action(C, NULL);
                        }
+                       
+                       /* clear action refs from editor, and then also the backing data (not necessary) */
+                       actedit_change_action(C, NULL);
                }
        }
        
@@ -359,6 +351,92 @@ void ACTION_OT_stash(wmOperatorType *ot)
                                   "Create a new action once the existing one has been safely stored");
 }
 
+/* ----------------- */
+
+/* Criteria:
+ *  1) There must be an dopesheet/action editor, and it must be in a mode which uses actions 
+ *  2) The associated AnimData block must not be in tweakmode
+ */
+static int action_stash_create_poll(bContext *C)
+{
+       if (ED_operator_action_active(C)) {
+               SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+               Scene *scene = CTX_data_scene(C);
+               
+               /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */
+               /* NOTE: unlike for pushdown, this operator needs to be run when creating an action from nothing... */
+               if (!(scene->flag & SCE_NLA_EDIT_ON)) {
+                       /* For now, actions are only for the active object, and on object and shapekey levels... */
+                       return ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY);
+               }
+       }
+       
+       /* something failed... */
+       return false;
+}
+
+static int action_stash_create_exec(bContext *C, wmOperator *op)
+{
+       SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C);
+       AnimData *adt = actedit_animdata_from_context(C);
+       
+       /* Check for no action... */
+       if (saction->action == NULL) {
+               /* just create a new action */
+               bAction *action = action_create_new(C, NULL);
+               actedit_change_action(C, action);
+       }
+       else if (adt) {
+               /* Perform stashing operation */
+               if (action_has_motion(adt->action) == 0) {
+                       /* don't do anything if this action is empty... */
+                       BKE_report(op->reports, RPT_WARNING, "Action needs have at least a keyframe or some FModifiers");
+                       return OPERATOR_CANCELLED;
+               }
+               else {
+                       /* stash the action */
+                       if (BKE_nla_action_stash(adt)) {
+                               bAction *new_action = NULL;
+                               
+                               /* create new action based on the old one */
+                               new_action = action_create_new(C, saction->action);
+                               
+                               /* The stash operation will remove the user already,
+                                * so the flushing step later shouldn't double up
+                                * the usercount fixes. Hence, we must unset this ref
+                                * first before setting the new action.
+                                */
+                               saction->action = NULL;
+                               actedit_change_action(C, new_action);
+                       }
+                       else {
+                               /* action has already been added - simply warn about this, and clear */
+                               BKE_report(op->reports, RPT_ERROR, "Action has already been stashed");
+                               actedit_change_action(C, NULL);
+                       }
+               }
+       }
+       
+       /* Send notifiers that stuff has changed */
+       WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+       return OPERATOR_FINISHED;
+}
+
+void ACTION_OT_stash_and_create(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Stash Action";
+       ot->idname = "ACTION_OT_stash_and_create";
+       ot->description = "Store this action in the NLA stack as a non-contributing strip for later use, and create a new action";
+       
+       /* callbacks */
+       ot->exec = action_stash_create_exec;
+       ot->poll = action_stash_create_poll;
+       
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
 /* ************************************************************************** */
 /* POSE MARKERS STUFF */
 
index f0f651dd07a690a0c50970044a04fe746711c37a..61d4249ae20f250e698197f0d3732a6f9e103e13 100644 (file)
@@ -103,6 +103,7 @@ void ACTION_OT_mirror(struct wmOperatorType *ot);
 void ACTION_OT_new(struct wmOperatorType *ot);
 void ACTION_OT_push_down(struct wmOperatorType *ot);
 void ACTION_OT_stash(struct wmOperatorType *ot);
+void ACTION_OT_stash_and_create(struct wmOperatorType *ot);
 
 void ACTION_OT_markers_make_local(struct wmOperatorType *ot);
 
index 0bf31d2dfb32551d8fcc9cfb414f8529fca79450..8c706d8da5773a2edc75277307822ae1e347cc4f 100644 (file)
@@ -81,6 +81,7 @@ void action_operatortypes(void)
        WM_operatortype_append(ACTION_OT_new);
        WM_operatortype_append(ACTION_OT_push_down);
        WM_operatortype_append(ACTION_OT_stash);
+       WM_operatortype_append(ACTION_OT_stash_and_create);
        
        WM_operatortype_append(ACTION_OT_previewrange_set);
        WM_operatortype_append(ACTION_OT_view_all);