2.5
authorTon Roosendaal <ton@blender.org>
Wed, 29 Jul 2009 17:56:38 +0000 (17:56 +0000)
committerTon Roosendaal <ton@blender.org>
Wed, 29 Jul 2009 17:56:38 +0000 (17:56 +0000)
Operator goodies!

--- Macro operators

Operators now can consist of multiple operators. Such a macro operator
is identical and behaves identical to other opererators. Macros can
also be constructed of macros even! Currently only hardcoded macros are
implemented, this to solve combined operators such as 'add duplicate' or
'extrude' (both want a transform appended).

Usage is simple:
- WM_operatortype_append_macro() : add new operatortype, name, flags
- WM_operatortype_macro_define() : add existing operator to macro

(Note: macro_define will also allow properties to be set, doesnt work
 right now)

On converting the macro wmOperatorType to a real operator, it makes a
list of all operators, and the standard macro callbacks (exec, invoke,
modal, poll) just will use all.

Important note; switching to a modal operator only works as last in the
chain now!

Macros implemented for duplicate, extrude and rip. Tool menu works fine
for it, also the redo hotkey F4 works properly.

--- Operator redo fix

The operators use the undo system to switch back, but this could give
errors if other actions added undo pushes (buttons, outliner). Now the
redo for operator searches back for the correct undo level.

This fixes issues with many redos.

Note for brecht: removed the ED_undo_push for buttons... it was called
on *every* button now, which is probably too much? For example, using
the 'toolbar' redo also caused this...

21 files changed:
source/blender/blenkernel/BKE_blender.h
source/blender/blenkernel/intern/blender.c
source/blender/editors/include/ED_util.h
source/blender/editors/interface/interface_handlers.c
source/blender/editors/mesh/editmesh_add.c
source/blender/editors/mesh/editmesh_tools.c
source/blender/editors/mesh/mesh_ops.c
source/blender/editors/object/object_edit.c
source/blender/editors/object/object_ops.c
source/blender/editors/space_view3d/view3d_edit.c
source/blender/editors/space_view3d/view3d_ops.c
source/blender/editors/space_view3d/view3d_toolbar.c
source/blender/editors/util/editmode_undo.c
source/blender/editors/util/undo.c
source/blender/editors/util/util_intern.h
source/blender/makesdna/DNA_windowmanager_types.h
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/WM_types.h
source/blender/windowmanager/intern/wm.c
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_operators.c

index 795c758..19b9c31 100644 (file)
@@ -71,6 +71,7 @@ void pushpop_test(void);
 /* global undo */
 extern void BKE_write_undo(struct bContext *C, char *name);
 extern void BKE_undo_step(struct bContext *C, int step);
+extern void BKE_undo_name(struct bContext *C, const char *name);
 extern void BKE_reset_undo(void);
 extern char *BKE_undo_menu_string(void);
 extern void BKE_undo_number(struct bContext *C, int nr);
index 2050535..2728aa3 100644 (file)
@@ -688,6 +688,22 @@ void BKE_undo_number(bContext *C, int nr)
        BKE_undo_step(C, 0);
 }
 
+/* go back to the last occurance of name in stack */
+void BKE_undo_name(bContext *C, const char *name)
+{
+       UndoElem *uel;
+       
+       for(uel= undobase.last; uel; uel= uel->prev) {
+               if(strcmp(name, uel->name)==0)
+                       break;
+       }
+       if(uel && uel->prev) {
+               curundo= uel->prev;
+               BKE_undo_step(C, 0);
+       }
+}
+
+
 char *BKE_undo_menu_string(void)
 {
        UndoElem *uel;
index 7ccbf1f..7b1c87f 100644 (file)
@@ -44,6 +44,7 @@ void  ED_editors_exit                 (struct bContext *C);
 /* undo.c */
 void   ED_undo_push                    (struct bContext *C, char *str);
 void   ED_undo_push_op                 (struct bContext *C, struct wmOperator *op);
+void   ED_undo_pop_op                  (struct bContext *C, struct wmOperator *op);
 void   ED_undo_pop                             (struct bContext *C);
 void   ED_undo_redo                    (struct bContext *C);
 void   ED_OT_undo                              (struct wmOperatorType *ot);
index da2899d..6f2b49c 100644 (file)
@@ -358,8 +358,8 @@ static void ui_apply_but_funcs_after(bContext *C)
                if(after.rename_orig)
                        MEM_freeN(after.rename_orig);
                
-               if(after.undostr[0])
-                       ED_undo_push(C, after.undostr);
+//             if(after.undostr[0])
+//                     ED_undo_push(C, after.undostr);
        }
 }
 
index 92aa46e..34eca87 100644 (file)
@@ -1683,9 +1683,6 @@ static int mesh_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
        mesh_duplicate_exec(C, op);
        WM_cursor_wait(0);
        
-       RNA_int_set(op->ptr, "mode", TFM_TRANSLATION);
-       WM_operator_name_call(C, "TFM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
-       
        return OPERATOR_FINISHED;
 }
 
index 76f355a..93e9173 100644 (file)
@@ -704,7 +704,7 @@ static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
        Scene *scene= CTX_data_scene(C);
        Object *obedit= CTX_data_edit_object(C);
        EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
-       int constraint_axis[3] = {0, 0, 1};
+//     int constraint_axis[3] = {0, 0, 1};
 
        extrude_mesh(scene, obedit, em, op);
 
@@ -717,11 +717,11 @@ static int mesh_extrude_invoke(bContext *C, wmOperator *op, wmEvent *event)
        RNA_boolean_set(op->ptr, "mirror", 0);
        
        /* the following two should only be set when extruding faces */
-       RNA_enum_set(op->ptr, "constraint_orientation", V3D_MANIP_NORMAL);
-       RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
+//     RNA_enum_set(op->ptr, "constraint_orientation", V3D_MANIP_NORMAL);
+//     RNA_boolean_set_array(op->ptr, "constraint_axis", constraint_axis);
        
        
-       WM_operator_name_call(C, "TFM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
+//     WM_operator_name_call(C, "TFM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
 
        return OPERATOR_FINISHED;
 }
@@ -4991,9 +4991,9 @@ static int mesh_rip_invoke(bContext *C, wmOperator *op, wmEvent *event)
 
        BKE_mesh_end_editmesh(obedit->data, em);
 
-       RNA_enum_set(op->ptr, "proportional", 0);
-       RNA_boolean_set(op->ptr, "mirror", 0);
-       WM_operator_name_call(C, "TFM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
+//     RNA_enum_set(op->ptr, "proportional", 0);
+//     RNA_boolean_set(op->ptr, "mirror", 0);
+//     WM_operator_name_call(C, "TFM_OT_translate", WM_OP_INVOKE_REGION_WIN, op->ptr);
 
        return OPERATOR_FINISHED;
 }
index 8ed68d5..edb131d 100644 (file)
@@ -230,6 +230,8 @@ static void MESH_OT_specials(wmOperatorType *ot)
 
 void ED_operatortypes_mesh(void)
 {
+       wmOperatorType *ot;
+       
        WM_operatortype_append(MESH_OT_select_all_toggle);
        WM_operatortype_append(MESH_OT_select_more);
        WM_operatortype_append(MESH_OT_select_less);
@@ -313,6 +315,20 @@ void ED_operatortypes_mesh(void)
        WM_operatortype_append(MESH_OT_edge_specials);
        WM_operatortype_append(MESH_OT_face_specials);
        WM_operatortype_append(MESH_OT_specials);
+       
+       /* macros */
+       ot= WM_operatortype_append_macro("MESH_OT_duplicate_move", "Add Duplicate", OPTYPE_UNDO|OPTYPE_REGISTER);
+       WM_operatortype_macro_define(ot, "MESH_OT_duplicate");
+       WM_operatortype_macro_define(ot, "TFM_OT_translate");
+
+       ot= WM_operatortype_append_macro("MESH_OT_rip_move", "Rip", OPTYPE_UNDO|OPTYPE_REGISTER);
+       WM_operatortype_macro_define(ot, "MESH_OT_rip");
+       WM_operatortype_macro_define(ot, "TFM_OT_translate");
+
+       ot= WM_operatortype_append_macro("MESH_OT_extrude_move", "Extrude", OPTYPE_UNDO|OPTYPE_REGISTER);
+       WM_operatortype_macro_define(ot, "MESH_OT_extrude");
+       WM_operatortype_macro_define(ot, "TFM_OT_translate");
+       
 }
 
 /* note mesh keymap also for other space? */
@@ -363,7 +379,7 @@ void ED_keymap_mesh(wmWindowManager *wm)
        WM_keymap_add_item(keymap, "MESH_OT_normals_make_consistent", NKEY, KM_PRESS, KM_CTRL, 0);
        RNA_boolean_set(WM_keymap_add_item(keymap, "MESH_OT_normals_make_consistent", NKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0)->ptr, "inside", 1);
        
-       WM_keymap_add_item(keymap, "MESH_OT_extrude", EKEY, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "MESH_OT_extrude_move", EKEY, KM_PRESS, 0, 0);
        
        WM_keymap_add_item(keymap, "MESH_OT_spin", RKEY, KM_PRESS, KM_ALT, 0);
        WM_keymap_add_item(keymap, "MESH_OT_screw", NINEKEY, KM_PRESS, KM_CTRL, 0);
@@ -386,12 +402,12 @@ void ED_keymap_mesh(wmWindowManager *wm)
        WM_keymap_add_item(keymap, "MESH_OT_colors_rotate",EIGHTKEY, KM_PRESS, KM_CTRL, 0);
        WM_keymap_add_item(keymap, "MESH_OT_colors_mirror",EIGHTKEY, KM_PRESS, KM_ALT, 0);
 
-       WM_keymap_add_item(keymap, "MESH_OT_rip",VKEY, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "MESH_OT_rip_move",VKEY, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "MESH_OT_merge", MKEY, KM_PRESS, KM_ALT, 0);
 
        /* add/remove */
        WM_keymap_add_item(keymap, "MESH_OT_edge_face_add", FKEY, KM_PRESS, 0, 0);
-       WM_keymap_add_item(keymap, "MESH_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
+       WM_keymap_add_item(keymap, "MESH_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
        WM_keymap_add_item(keymap, "OBJECT_OT_mesh_add", AKEY, KM_PRESS, KM_SHIFT, 0);
        WM_keymap_add_item(keymap, "MESH_OT_separate", PKEY, KM_PRESS, KM_SHIFT, 0);
                                                /* use KM_RELEASE because same key is used for tweaks */
index f34dc2e..5fd5f4f 100644 (file)
@@ -6497,8 +6497,8 @@ static int duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
        duplicate_exec(C, op);
        
-       RNA_int_set(op->ptr, "mode", TFM_TRANSLATION);
-       WM_operator_name_call(C, "TFM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
+//     RNA_int_set(op->ptr, "mode", TFM_TRANSLATION);
+//     WM_operator_name_call(C, "TFM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
 
        return OPERATOR_FINISHED;
 }
index fe09284..c1509e7 100644 (file)
@@ -63,6 +63,8 @@
 
 void ED_operatortypes_object(void)
 {
+       wmOperatorType *ot;
+       
        WM_operatortype_append(OBJECT_OT_editmode_toggle);
        WM_operatortype_append(OBJECT_OT_posemode_toggle);
        WM_operatortype_append(OBJECT_OT_parent_set);
@@ -147,6 +149,13 @@ void ED_operatortypes_object(void)
 
        WM_operatortype_append(LATTICE_OT_select_all_toggle);
        WM_operatortype_append(LATTICE_OT_make_regular);
+       
+       /* macros */
+       ot= WM_operatortype_append_macro("OBJECT_OT_duplicate_move", "Add Duplicate", OPTYPE_UNDO|OPTYPE_REGISTER);
+       if(ot) {
+               WM_operatortype_macro_define(ot, "OBJECT_OT_duplicate");
+               WM_operatortype_macro_define(ot, "TFM_OT_translate");
+       }
 }
 
 void ED_keymap_object(wmWindowManager *wm)
@@ -185,7 +194,7 @@ void ED_keymap_object(wmWindowManager *wm)
        
        WM_keymap_verify_item(keymap, "OBJECT_OT_delete", XKEY, KM_PRESS, 0, 0);
        WM_keymap_verify_item(keymap, "OBJECT_OT_primitive_add", AKEY, KM_PRESS, KM_SHIFT, 0);
-       WM_keymap_add_item(keymap, "OBJECT_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
+       WM_keymap_add_item(keymap, "OBJECT_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
        RNA_boolean_set(WM_keymap_add_item(keymap, "OBJECT_OT_duplicate", DKEY, KM_PRESS, KM_ALT, 0)->ptr, "linked", 1);
        WM_keymap_add_item(keymap, "OBJECT_OT_join", JKEY, KM_PRESS, KM_CTRL, 0);
        WM_keymap_add_item(keymap, "OBJECT_OT_proxy_make", PKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
index f278b71..acb3a22 100644 (file)
@@ -560,7 +560,7 @@ void VIEW3D_OT_viewrotate(wmOperatorType *ot)
        ot->poll= ED_operator_view3d_active;
 
        /* flags */
-       ot->flag= OPTYPE_REGISTER|OPTYPE_BLOCKING;
+       ot->flag= OPTYPE_BLOCKING;
 }
 
 /* ************************ viewmove ******************************** */
@@ -644,7 +644,7 @@ void VIEW3D_OT_viewmove(wmOperatorType *ot)
        ot->poll= ED_operator_view3d_active;
 
        /* flags */
-       ot->flag= OPTYPE_REGISTER|OPTYPE_BLOCKING;
+       ot->flag= OPTYPE_BLOCKING;
 }
 
 /* ************************ viewzoom ******************************** */
@@ -844,7 +844,7 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
        ot->poll= ED_operator_view3d_active;
 
        /* flags */
-       ot->flag= OPTYPE_REGISTER|OPTYPE_BLOCKING;
+       ot->flag= OPTYPE_BLOCKING;
 
        RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
 }
@@ -925,7 +925,7 @@ void VIEW3D_OT_view_all(wmOperatorType *ot)
        ot->poll= ED_operator_view3d_active;
 
        /* flags */
-       ot->flag= OPTYPE_REGISTER;
+       ot->flag= 0;
 
        RNA_def_boolean(ot->srna, "center", 0, "Center", "");
 }
@@ -1064,7 +1064,7 @@ void VIEW3D_OT_view_center(wmOperatorType *ot)
        ot->poll= ED_operator_view3d_active;
 
        /* flags */
-       ot->flag= OPTYPE_REGISTER;
+       ot->flag= 0;
 }
 
 /* ********************* Set render border operator ****************** */
@@ -1312,7 +1312,7 @@ void VIEW3D_OT_zoom_border(wmOperatorType *ot)
        ot->poll= ED_operator_view3d_active;
 
        /* flags */
-       ot->flag= OPTYPE_REGISTER;
+       ot->flag= 0;
 
        /* rna */
        RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
@@ -1477,7 +1477,7 @@ void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
        ot->poll= ED_operator_view3d_active;
 
        /* flags */
-       ot->flag= OPTYPE_REGISTER;
+       ot->flag= 0;
 
        RNA_def_enum(ot->srna, "type", prop_view_items, 0, "View", "The Type of view");
 }
@@ -1546,7 +1546,7 @@ void VIEW3D_OT_view_orbit(wmOperatorType *ot)
        ot->poll= ED_operator_view3d_active;
 
        /* flags */
-       ot->flag= OPTYPE_REGISTER;
+       ot->flag= 0;
        RNA_def_enum(ot->srna, "type", prop_view_orbit_items, 0, "Orbit", "Direction of View Orbit");
 }
 
@@ -1596,7 +1596,7 @@ void VIEW3D_OT_view_pan(wmOperatorType *ot)
        ot->poll= ED_operator_view3d_active;
 
        /* flags */
-       ot->flag= OPTYPE_REGISTER;
+       ot->flag= 0;
        RNA_def_enum(ot->srna, "type", prop_view_pan_items, 0, "Pan", "Direction of View Pan");
 }
 
@@ -1628,7 +1628,7 @@ void VIEW3D_OT_view_persportho(wmOperatorType *ot)
        ot->poll= ED_operator_view3d_active;
 
        /* flags */
-       ot->flag= OPTYPE_REGISTER;
+       ot->flag= 0;
 }
 
 
@@ -1730,7 +1730,7 @@ void VIEW3D_OT_clip_border(wmOperatorType *ot)
        ot->poll= ED_operator_view3d_active;
 
        /* flags */
-       ot->flag= OPTYPE_REGISTER;
+       ot->flag= 0;
 
        /* rna */
        RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
@@ -1783,7 +1783,7 @@ void VIEW3D_OT_drawtype(wmOperatorType *ot)
        ot->poll= ED_operator_view3d_active;
 
        /* flags */
-       ot->flag= OPTYPE_REGISTER;
+       ot->flag= 0;
 
        /* rna XXX should become enum */
        RNA_def_int(ot->srna, "draw_type", 0, INT_MIN, INT_MAX, "Draw Type", "", INT_MIN, INT_MAX);
index 69b297b..c82db3b 100644 (file)
@@ -218,8 +218,8 @@ void view3d_keymap(wmWindowManager *wm)
        
        WM_keymap_add_item(keymap, "VIEW3D_OT_snap_menu", SKEY, KM_PRESS, KM_SHIFT, 0);
 
-       /* drag & drop */
-       WM_keymap_add_item(keymap, "VIEW3D_OT_drag", MOUSEDRAG, KM_ANY, 0, 0);
+       /* drag & drop (disabled) */
+//     WM_keymap_add_item(keymap, "VIEW3D_OT_drag", MOUSEDRAG, KM_ANY, 0, 0);
        
        /* radial control */
        RNA_enum_set(WM_keymap_add_item(keymap, "SCULPT_OT_radial_control", FKEY, KM_PRESS, 0, 0)->ptr, "mode", WM_RADIALCONTROL_SIZE);
index 1564fcb..67d8bc3 100644 (file)
@@ -109,7 +109,7 @@ static void redo_cb(bContext *C, void *arg_op, void *arg2)
                int retval;
                
                printf("operator redo %s\n", lastop->type->name);
-               ED_undo_pop(C);
+               ED_undo_pop_op(C, lastop);
                retval= WM_operator_repeat(C, lastop);
                if((retval & OPERATOR_FINISHED)==0) {
                        printf("operator redo failed %s\n", lastop->type->name);
@@ -118,11 +118,25 @@ static void redo_cb(bContext *C, void *arg_op, void *arg2)
        }
 }
 
+static void view3d_panel_operator_redo_buts(const bContext *C, Panel *pa, wmOperator *op)
+{
+       wmWindowManager *wm= CTX_wm_manager(C);
+       PointerRNA ptr;
+       
+       if(!op->properties) {
+               IDPropertyTemplate val = {0};
+               op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
+       }
+       
+       RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
+       uiDefAutoButsRNA(C, pa->layout, &ptr, 1);
+       
+}
+
 static void view3d_panel_operator_redo(const bContext *C, Panel *pa)
 {
        wmWindowManager *wm= CTX_wm_manager(C);
        wmOperator *op;
-       PointerRNA ptr;
        uiBlock *block;
        
        block= uiLayoutGetBlock(pa->layout);
@@ -139,13 +153,13 @@ static void view3d_panel_operator_redo(const bContext *C, Panel *pa)
        
        uiBlockSetFunc(block, redo_cb, op, NULL);
        
-       if(!op->properties) {
-               IDPropertyTemplate val = {0};
-               op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
+       if(op->macro.first) {
+               for(op= op->macro.first; op; op= op->next)
+                       view3d_panel_operator_redo_buts(C, pa, op);
+       }
+       else {
+               view3d_panel_operator_redo_buts(C, pa, op);
        }
-       
-       RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
-       uiDefAutoButsRNA(C, pa->layout, &ptr, 1);
 }
 
 /* ******************* */
index 8484ad7..17a1e0b 100644 (file)
@@ -297,6 +297,21 @@ static void undo_number(bContext *C, int nr)
        undo_editmode_step(C, 0);
 }
 
+void undo_editmode_name(bContext *C, const char *undoname)
+{
+       UndoElem *uel;
+       
+       for(uel= undobase.last; uel; uel= uel->prev) {
+               if(strcmp(undoname, uel->name)==0)
+                       break;
+       }
+       if(uel && uel->prev) {
+               curundo= uel->prev;
+               undo_editmode_step(C, 0);
+       }
+}
+
+
 /* ************** for interaction with menu/pullown */
 
 void undo_editmode_menu(bContext *C)
index be04cde..435f2c7 100644 (file)
@@ -71,6 +71,8 @@
 #include "UI_interface.h"
 #include "UI_resources.h"
 
+#include "util_intern.h"
+
 /* ***************** generic undo system ********************* */
 
 /* ********* XXX **************** */
@@ -81,7 +83,7 @@ void ED_undo_push(bContext *C, char *str)
 {
        wmWindowManager *wm= CTX_wm_manager(C);
        Object *obedit= CTX_data_edit_object(C);
-       
+
        if(obedit) {
                if (U.undosteps == 0) return;
                
@@ -114,13 +116,7 @@ void ED_undo_push(bContext *C, char *str)
        }
 }
 
-void ED_undo_push_op(bContext *C, wmOperator *op)
-{
-       /* in future, get undo string info? */
-       ED_undo_push(C, op->type->name);
-}
-
-static int ed_undo_step(bContext *C, int step)
+static int ed_undo_step(bContext *C, int step, const char *undoname)
 {      
        Object *obedit= CTX_data_edit_object(C);
        ScrArea *sa= CTX_wm_area(C);
@@ -140,8 +136,12 @@ static int ed_undo_step(bContext *C, int step)
                ED_text_undo_step(C, step);
        }
        else if(obedit) {
-               if ELEM7(obedit->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE)
-                       undo_editmode_step(C, step);
+               if ELEM7(obedit->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE) {
+                       if(undoname)
+                               undo_editmode_name(C, undoname);
+                       else
+                               undo_editmode_step(C, step);
+               }
        }
        else {
                int do_glob_undo= 0;
@@ -163,7 +163,10 @@ static int ed_undo_step(bContext *C, int step)
 #ifndef DISABLE_PYTHON
                                // XXX          BPY_scripts_clear_pyobjects();
 #endif
-                               BKE_undo_step(C, step);
+                               if(undoname)
+                                       BKE_undo_name(C, undoname);
+                               else
+                                       BKE_undo_step(C, step);
                                sound_initialize_sounds();
                        }
                        
@@ -177,22 +180,35 @@ static int ed_undo_step(bContext *C, int step)
 
 void ED_undo_pop(bContext *C)
 {
-       ed_undo_step(C, 1);
+       ed_undo_step(C, 1, NULL);
 }
 void ED_undo_redo(bContext *C)
 {
-       ed_undo_step(C, -1);
+       ed_undo_step(C, -1, NULL);
+}
+
+void ED_undo_push_op(bContext *C, wmOperator *op)
+{
+       /* in future, get undo string info? */
+       ED_undo_push(C, op->type->name);
+}
+
+void ED_undo_pop_op(bContext *C, wmOperator *op)
+{
+       /* search back a couple of undo's, in case something else added pushes */
+       ed_undo_step(C, 0, op->type->name);
 }
 
 static int ed_undo_exec(bContext *C, wmOperator *op)
 {
        /* "last operator" should disappear, later we can tie ths with undo stack nicer */
        WM_operator_stack_clear(C);
-       return ed_undo_step(C, 1);
+       return ed_undo_step(C, 1, NULL);
 }
+
 static int ed_redo_exec(bContext *C, wmOperator *op)
 {
-       return ed_undo_step(C, -1);
+       return ed_undo_step(C, -1, NULL);
 }
 
 void ED_undo_menu(bContext *C)
index 37e6c5c..8a0787d 100644 (file)
@@ -33,6 +33,7 @@
 
 /* editmode_undo.c */
 void undo_editmode_clear(void);
+void undo_editmode_name(bContext *C, const char *undoname);
 
 #endif /* ED_UTIL_INTERN_H */
 
index a7ad502..704acbf 100644 (file)
@@ -171,6 +171,18 @@ typedef struct wmWindow {
 /* should be somthing like DNA_EXCLUDE 
  * but the preprocessor first removes all comments, spaces etc */
 
+#
+#
+typedef struct wmOperatorTypeMacro {
+       struct wmOperatorTypeMacro *next, *prev;
+       
+       /* operator id */
+       char idname[MAX_ID_NAME];
+       /* rna pointer to access properties, like keymap */
+       struct PointerRNA *ptr; 
+
+} wmOperatorTypeMacro;
+
 #
 #
 typedef struct wmOperatorType {
@@ -204,6 +216,9 @@ typedef struct wmOperatorType {
        /* rna for properties */
        struct StructRNA *srna;
        
+       /* struct wmOperatorTypeMacro */
+       ListBase macro;
+       
        short flag;
        
        /* pointer to modal keymap, do not free! */
@@ -265,9 +280,13 @@ typedef struct wmOperator {
        /* runtime */
        wmOperatorType *type;           /* operator type definition from idname */
        void *customdata;                       /* custom storage, only while operator runs */
+       
        struct PointerRNA *ptr;         /* rna pointer to access properties */
        struct ReportList *reports;     /* errors and warnings storage */
        
+       ListBase macro;                         /* list of operators, can be a tree */
+       struct wmOperator *opm;         /* current running macro, not saved */
+       
 } wmOperator;
 
 /* operator type exec(), invoke() modal(), return values */
index 0d3ad96..f65e5b1 100644 (file)
@@ -158,6 +158,10 @@ void               WM_operatortype_append  (void (*opfunc)(wmOperatorType*));
 void           WM_operatortype_append_ptr      (void (*opfunc)(wmOperatorType*, void *), void *userdata);
 int                    WM_operatortype_remove(const char *idname);
 
+wmOperatorType *WM_operatortype_append_macro(char *idname, char *name, int flag);
+wmOperatorTypeMacro *WM_operatortype_macro_define(wmOperatorType *ot, const char *idname);
+
+
 int                    WM_operator_call                (struct bContext *C, struct wmOperator *op);
 int                    WM_operator_repeat              (struct bContext *C, struct wmOperator *op);
 int         WM_operator_name_call      (struct bContext *C, const char *opstring, int context, struct PointerRNA *properties);
index 3a646c5..a083d58 100644 (file)
@@ -43,6 +43,7 @@ struct wmWindowManager;
 #define OPTYPE_REGISTER                1       /* register operators in stack after finishing */
 #define OPTYPE_UNDO                    2       /* do undo push after after */
 #define OPTYPE_BLOCKING                4       /* let blender grab all input from the WM (X11) */
+#define OPTYPE_MACRO           8
 
 /* context to call operator in for WM_operator_name_call */
 /* rna_ui.c contains EnumPropertyItem's of these, keep in sync */
index 863fb3a..c0ac7b0 100644 (file)
@@ -74,6 +74,12 @@ void WM_operator_free(wmOperator *op)
                MEM_freeN(op->reports);
        }
 
+       if(op->macro.first) {
+               wmOperator *opm;
+               for(opm= op->macro.first; opm; opm= opm->next) 
+                       WM_operator_free(opm);
+       }
+       
        MEM_freeN(op);
 }
 
index c75feaf..33e8a39 100644 (file)
@@ -244,6 +244,23 @@ void wm_event_do_notifiers(bContext *C)
 
 /* ********************* operators ******************* */
 
+static int wm_operator_poll(bContext *C, wmOperatorType *ot)
+{
+       wmOperatorTypeMacro *otmacro;
+       
+       for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
+               wmOperatorType *ot= WM_operatortype_find(otmacro->idname, 0);
+               
+               if(0==wm_operator_poll(C, ot))
+                       return 0;
+       }
+       
+       if(ot->poll)
+               return ot->poll(C);
+       
+       return 1;
+}
+
 /* if repeat is true, it doesn't register again, nor does it free */
 static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
 {
@@ -252,7 +269,7 @@ static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
        if(op==NULL || op->type==NULL)
                return retval;
        
-       if(op->type->poll && op->type->poll(C)==0)
+       if(0==wm_operator_poll(C, op->type))
                return retval;
        
        if(op->type->exec)
@@ -320,6 +337,26 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, P
                BKE_reports_init(op->reports, RPT_STORE);
        }
        
+       /* recursive filling of operator macro list */
+       if(ot->macro.first) {
+               static wmOperator *motherop= NULL;
+               wmOperatorTypeMacro *otmacro;
+               
+               /* ensure all ops are in execution order in 1 list */
+               if(motherop==NULL) 
+                       motherop= op;
+               
+               for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
+                       wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0);
+                       wmOperator *opm= wm_operator_create(wm, otm, otmacro->ptr, NULL);
+                       
+                       BLI_addtail(&motherop->macro, opm);
+                       opm->opm= motherop; /* pointer to mom, for modal() */
+               }
+               
+               motherop= NULL;
+       }
+       
        return op;
 }
 
@@ -345,7 +382,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
        wmWindowManager *wm= CTX_wm_manager(C);
        int retval= OPERATOR_PASS_THROUGH;
 
-       if(ot->poll==NULL || ot->poll(C)) {
+       if(wm_operator_poll(C, ot)) {
                wmOperator *op= wm_operator_create(wm, ot, properties, NULL);
                
                if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE)
@@ -809,7 +846,6 @@ static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHa
                case EVT_FILESELECT_OPEN: 
                case EVT_FILESELECT_FULL_OPEN: 
                        {
-                               short flag =0; short display =FILE_SHORTDISPLAY; short filter =0; short sort =FILE_SORT_ALPHA;
                                char *dir= NULL; char *path= RNA_string_get_alloc(handler->op->ptr, "filename", NULL, 0);
                                        
                                if(event->val==EVT_FILESELECT_OPEN)
@@ -1198,7 +1234,17 @@ void WM_event_set_handler_flag(wmEventHandler *handler, int flag)
 wmEventHandler *WM_event_add_modal_handler(bContext *C, ListBase *handlers, wmOperator *op)
 {
        wmEventHandler *handler= MEM_callocN(sizeof(wmEventHandler), "event modal handler");
-       handler->op= op;
+       
+       /* operator was part of macro */
+       if(op->opm) {
+               /* give the mother macro to the handler */
+               handler->op= op->opm;
+               /* mother macro opm becomes the macro element */
+               handler->op->opm= op;
+       }
+       else
+               handler->op= op;
+       
        handler->op_area= CTX_wm_area(C);               /* means frozen screen context for modal handlers! */
        handler->op_region= CTX_wm_region(C);
        
index e25c86e..2b7a18d 100644 (file)
@@ -154,6 +154,134 @@ void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType*, void*), void *us
        BLI_addtail(&global_ops, ot);
 }
 
+/* ********************* macro operator ******************** */
+
+/* macro exec only runs exec calls */
+static int wm_macro_exec(bContext *C, wmOperator *op)
+{
+       wmOperator *opm;
+       int retval= OPERATOR_FINISHED;
+       
+//     printf("macro exec %s\n", op->type->idname);
+       
+       for(opm= op->macro.first; opm; opm= opm->next) {
+               
+               if(opm->type->exec) {
+//                     printf("macro exec %s\n", opm->type->idname);
+                       retval= opm->type->exec(C, opm);
+               
+                       if(!(retval & OPERATOR_FINISHED))
+                               break;
+               }
+       }
+//     if(opm)
+//             printf("macro ended not finished\n");
+//     else
+//             printf("macro end\n");
+       
+       return retval;
+}
+
+static int wm_macro_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       wmOperator *opm;
+       int retval= OPERATOR_FINISHED;
+       
+//     printf("macro invoke %s\n", op->type->idname);
+       
+       for(opm= op->macro.first; opm; opm= opm->next) {
+               
+               if(opm->type->invoke)
+                       retval= opm->type->invoke(C, opm, event);
+               else if(opm->type->exec)
+                       retval= opm->type->exec(C, opm);
+               
+               if(!(retval & OPERATOR_FINISHED))
+                       break;
+       }
+       
+//     if(opm)
+//             printf("macro ended not finished\n");
+//     else
+//             printf("macro end\n");
+       
+       
+       return retval;
+}
+
+static int wm_macro_modal(bContext *C, wmOperator *op, wmEvent *event)
+{
+//     printf("macro modal %s\n", op->type->idname);
+       
+       if(op->opm==NULL)
+               printf("macro error, calling NULL modal()\n");
+       else {
+//             printf("macro modal %s\n", op->opm->type->idname);
+               return op->opm->type->modal(C, op->opm, event);
+       }       
+       
+       return OPERATOR_FINISHED;
+}
+
+/* Names have to be static for now */
+wmOperatorType *WM_operatortype_append_macro(char *idname, char *name, int flag)
+{
+       wmOperatorType *ot;
+       
+       if(WM_operatortype_exists(idname)) {
+               printf("Macro error: operator %s exists\n", idname);
+               return NULL;
+       }
+       
+       ot= MEM_callocN(sizeof(wmOperatorType), "operatortype");
+       ot->srna= RNA_def_struct(&BLENDER_RNA, "", "OperatorProperties");
+       
+       ot->idname= idname;
+       ot->name= name;
+       ot->flag= OPTYPE_MACRO | flag;
+       
+       ot->exec= wm_macro_exec;
+       ot->invoke= wm_macro_invoke;
+       ot->modal= wm_macro_modal;
+       ot->poll= NULL;
+       
+       RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description:"(undocumented operator)"); // XXX All ops should have a description but for now allow them not to.
+       RNA_def_struct_identifier(ot->srna, ot->idname);
+
+       BLI_addtail(&global_ops, ot);
+
+       return ot;
+}
+
+wmOperatorTypeMacro *WM_operatortype_macro_define(wmOperatorType *ot, const char *idname)
+{
+       wmOperatorTypeMacro *otmacro= MEM_callocN(sizeof(wmOperatorTypeMacro), "wmOperatorTypeMacro");
+       
+       BLI_strncpy(otmacro->idname, idname, OP_MAX_TYPENAME);
+
+       /* do this on first use, since operatordefinitions might have been not done yet */
+//     otmacro->ptr= MEM_callocN(sizeof(PointerRNA), "optype macro ItemPtr");
+//     WM_operator_properties_create(otmacro->ptr, idname);
+       
+       BLI_addtail(&ot->macro, otmacro);
+       
+       return otmacro;
+}
+
+static void wm_operatortype_free_macro(wmOperatorType *ot)
+{
+       wmOperatorTypeMacro *otmacro;
+       
+       for(otmacro= ot->macro.first; otmacro; otmacro= otmacro->next) {
+               if(otmacro->ptr) {
+                       WM_operator_properties_free(otmacro->ptr);
+                       MEM_freeN(otmacro->ptr);
+               }
+       }
+       BLI_freelistN(&ot->macro);
+}
+
+
 int WM_operatortype_remove(const char *idname)
 {
        wmOperatorType *ot = WM_operatortype_find(idname, 0);
@@ -163,6 +291,10 @@ int WM_operatortype_remove(const char *idname)
        
        BLI_remlink(&global_ops, ot);
        RNA_struct_free(&BLENDER_RNA, ot->srna);
+       
+       if(ot->macro.first)
+               wm_operatortype_free_macro(ot);
+       
        MEM_freeN(ot);
 
        return 1;
@@ -348,7 +480,7 @@ static void redo_cb(bContext *C, void *arg_op, void *arg2)
        wmOperator *lastop= arg_op;
        
        if(lastop) {
-               ED_undo_pop(C);
+               ED_undo_pop_op(C, lastop);
                WM_operator_repeat(C, lastop);
        }
 }
@@ -1677,6 +1809,12 @@ static void WM_OT_ten_timer(wmOperatorType *ot)
 /* called on initialize WM_exit() */
 void wm_operatortype_free(void)
 {
+       wmOperatorType *ot;
+       
+       for(ot= global_ops.first; ot; ot= ot->next)
+               if(ot->macro.first)
+                       wm_operatortype_free_macro(ot);
+       
        BLI_freelistN(&global_ops);
 }