diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 29d1d653b39..6d0c12210de 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -35,6 +35,7 @@ struct ListBase; struct ARegion; struct wmWindow; struct wmWindowManager; +struct wmOperator; struct AutoComplete; struct bContext; struct PointerRNA; @@ -194,7 +195,10 @@ typedef struct uiMenuBlockHandle { int popup; void (*popup_func)(struct bContext *C, void *arg, int event); void *popup_arg; - + /* for operator menus */ + struct wmOperator *op_arg; + const char *propname; + /* return values */ int butretval; int menuretval; @@ -206,8 +210,9 @@ typedef uiBlock* (*uiBlockFuncFP)(struct bContext *C, struct uiMenuBlockHandle * typedef void (*uiPupmenuFunc)(struct bContext *C, void *arg, int event); void uiPupmenuSetActive(int val); -void uiPupmenu(struct bContext *C, int maxrow, uiPupmenuFunc func, void *arg, char *str, ...); +void uiPupmenuOperator(struct bContext *C, int maxrow, struct wmOperator *op, const char *propname, char *str); +void uiPupmenu(struct bContext *C, int maxrow, uiPupmenuFunc func, void *arg, char *str, ...); void uiPupmenuOkee(struct bContext *C, char *opname, char *str, ...); void uiPupmenuSaveOver(struct bContext *C, char *opname, char *filename, ...); void uiPupmenuNotice(struct bContext *C, char *str, ...); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index a368f488d1a..d7235af14bc 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -53,6 +53,8 @@ #include "UI_text.h" #include "interface.h" +#include "RNA_access.h" + #include "WM_api.h" #include "WM_types.h" @@ -214,7 +216,7 @@ static void ui_apply_but_funcs_after(bContext *C) after->butm_func(C, after->butm_func_arg, after->a2); if(after->opname) - WM_operator_call(C, after->opname, after->opcontext, after->opproperties); + WM_operator_name_call(C, after->opname, after->opcontext, after->opproperties); if(after->opproperties) { IDP_FreeProperty(after->opproperties); MEM_freeN(after->opproperties); @@ -3647,28 +3649,35 @@ static int ui_handler_region_menu(bContext *C, wmEvent *event, void *userdata) return WM_UI_HANDLER_BREAK; } +/* two types of popups, one with operator + enum, other with regular callbacks */ static int ui_handler_popup(bContext *C, wmEvent *event, void *userdata) { uiMenuBlockHandle *menu= userdata; - void (*popup_func)(struct bContext *C, void *arg, int event)= NULL; - void *popup_arg= NULL; - int retval= 0; ui_handle_menus_recursive(C, event, menu); /* free if done, does not free handle itself */ if(menu->menuretval) { - if(menu->menuretval == UI_RETURN_OK) { - popup_func= menu->popup_func; - popup_arg= menu->popup_arg; - retval= menu->retvalue; - } - + /* copy values, we have to free first (closes region) */ + uiMenuBlockHandle temp= *menu; + ui_menu_block_free(C, menu); WM_event_remove_ui_handler(&CTX_wm_window(C)->handlers, ui_handler_popup, ui_handler_remove_popup, menu); - if(popup_func) - popup_func(C, popup_arg, retval); + if(temp.menuretval == UI_RETURN_OK) { + if(temp.popup_func) { + temp.popup_func(C, temp.op_arg, temp.retvalue); + } + else if(temp.op_arg) { + if(temp.propname) + RNA_enum_set(temp.op_arg->ptr, temp.propname, temp.retvalue); + WM_operator_call(C, temp.op_arg); + } + } + /* always free operator */ + else if(temp.op_arg) + WM_operator_free(temp.op_arg); + } else { /* re-enable tooltips */ @@ -3704,4 +3713,3 @@ void UI_add_popup_handlers(ListBase *handlers, uiMenuBlockHandle *menu) { WM_event_add_ui_handler(NULL, handlers, ui_handler_popup, ui_handler_remove_popup, menu); } - diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index d5b49fa801d..fe7e236a841 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -1629,6 +1629,33 @@ uiBlock *ui_block_func_PUPMENUCOL(bContext *C, uiMenuBlockHandle *handle, void * return block; } +/* This one will set enum propname, call operator and register it, and free the operator itself, + call it in op->invoke with returning OPERATOR_RUNNING_MODAL */ +/* Note: propname has to be static */ +void uiPupmenuOperator(bContext *C, int maxrow, wmOperator *op, const char *propname, char *str) +{ + wmWindow *window= CTX_wm_window(C); + uiPupMenuInfo info; + uiMenuBlockHandle *menu; + + memset(&info, 0, sizeof(info)); + info.mx= window->eventstate->x; + info.my= window->eventstate->y; + info.maxrow= maxrow; + info.instr= str; + + menu= ui_menu_block_create(C, NULL, NULL, ui_block_func_PUPMENU, &info); + menu->popup= 1; + + UI_add_popup_handlers(&window->handlers, menu); + WM_event_add_mousemove(C); + + menu->op_arg= op; + menu->propname= propname; +} + + +/* this one only to be called with operatortype name option */ void uiPupmenu(bContext *C, int maxrow, uiPupmenuFunc func, void *arg, char *str, ...) { wmWindow *window= CTX_wm_window(C); @@ -1658,7 +1685,7 @@ static void operator_cb(bContext *C, void *arg, int retval) const char *opname= arg; if(opname && retval > 0) - WM_operator_call(C, opname, WM_OP_DEFAULT, NULL); + WM_operator_name_call(C, opname, WM_OP_DEFAULT, NULL); } static void vconfirm(bContext *C, char *opname, char *title, char *itemfmt, va_list ap) diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 7be4adcc0b8..6e7fed9acf7 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -1512,16 +1512,6 @@ static int make_parent_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -static void makeparent_callback(bContext *C, void *arg, int event) -{ - wmOperator *op= (wmOperator *)arg; - - /* set the properties for the exec */ - RNA_enum_set(op->ptr, "partype", event); - - make_parent_exec(C, op); -} - static int make_parent_invoke(bContext *C, wmOperator *op, wmEvent *event) { Object *ob= CTX_data_active_object(C); @@ -1549,7 +1539,7 @@ static int make_parent_invoke(bContext *C, wmOperator *op, wmEvent *event) else str += sprintf(str, formatstr, "Object", PAR_OBJECT); - uiPupmenu(C, 0, makeparent_callback, op, string); + uiPupmenuOperator(C, 0, op, "partype", string); return OPERATOR_RUNNING_MODAL; } diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index 71637f5b1d6..32425b59d7b 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -461,7 +461,7 @@ static void do_view3d_view_alignviewmenu(bContext *C, void *arg, int event) // XXX mainqenter(PADASTERKEY, 1); break; case 6: /* Center View and Cursor to Origin */ - WM_operator_call(C, "ED_VIEW3D_OT_viewcenter", WM_OP_REGION_WIN, NULL); + WM_operator_name_call(C, "ED_VIEW3D_OT_viewcenter", WM_OP_REGION_WIN, NULL); curs= give_cursor(scene, v3d); curs[0]=curs[1]=curs[2]= 0.0; break; @@ -545,10 +545,10 @@ static void do_view3d_viewmenu(bContext *C, void *arg, int event) endlocalview(scene, sa); break; case 9: /* View All (Home) */ - WM_operator_call(C, "ED_VIEW3D_OT_viewhome", WM_OP_REGION_WIN, NULL); + WM_operator_name_call(C, "ED_VIEW3D_OT_viewhome", WM_OP_REGION_WIN, NULL); break; case 11: /* View Selected */ - WM_operator_call(C, "ED_VIEW3D_OT_viewcenter", WM_OP_REGION_WIN, NULL); + WM_operator_name_call(C, "ED_VIEW3D_OT_viewcenter", WM_OP_REGION_WIN, NULL); break; case 13: /* Play Back Animation */ play_anim(0); @@ -560,7 +560,7 @@ static void do_view3d_viewmenu(bContext *C, void *arg, int event) add_blockhandler(sa, VIEW3D_HANDLER_PROPERTIES, UI_PNL_UNSTOW); break; case 17: /* Set Clipping Border */ - WM_operator_call(C, "ED_VIEW3D_OT_clipping", WM_OP_REGION_WIN, NULL); + WM_operator_name_call(C, "ED_VIEW3D_OT_clipping", WM_OP_REGION_WIN, NULL); break; case 18: /* render preview */ toggle_blockhandler(sa, VIEW3D_HANDLER_PREVIEW, 0); @@ -5325,7 +5325,7 @@ static void do_view3d_buttons(bContext *C, void *arg, int event) switch(event) { case B_HOME: - WM_operator_call(C, "ED_VIEW3D_OT_viewhome", WM_OP_REGION_WIN, NULL); + WM_operator_name_call(C, "ED_VIEW3D_OT_viewhome", WM_OP_REGION_WIN, NULL); break; case B_SCENELOCK: if(v3d->scenelock) { diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index 85badf18bb7..0da0782c2d1 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -110,7 +110,7 @@ static PyObject * pyop_func_call(BPy_OperatorFunc * self, PyObject *args, PyObje } } - WM_operator_call(self->C, self->name, WM_OP_DEFAULT, properties); + WM_operator_name_call(self->C, self->name, WM_OP_DEFAULT, properties); if (properties) { IDP_FreeProperty(properties); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 6a91e3c538b..60f39e4dd9c 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -114,11 +114,13 @@ int WM_operator_winactive (struct bContext *C); void WM_error(struct bContext *C, char *str); /* operator api */ +void WM_operator_free (struct wmOperator *op); wmOperatorType *WM_operatortype_find(const char *idname); wmOperatorType *WM_operatortype_first(void); void WM_operatortype_append (void (*opfunc)(wmOperatorType*)); -int WM_operator_call (struct bContext *C, const char *opstring, int context, struct IDProperty *properties); +int WM_operator_call (struct bContext *C, struct wmOperator *op); +int WM_operator_name_call (struct bContext *C, const char *opstring, int context, struct IDProperty *properties); /* default operator callbacks for border/circle/lasso */ int WM_border_select_invoke (struct bContext *C, wmOperator *op, struct wmEvent *event); diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 32d55fe6273..725e9cd989e 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -51,7 +51,7 @@ #define MAX_OP_REGISTERED 32 -void wm_operator_free(wmOperator *op) +void WM_operator_free(wmOperator *op) { if(op->properties) { IDP_FreeProperty(op->properties); @@ -80,7 +80,7 @@ void wm_operator_register(wmWindowManager *wm, wmOperator *op) while(tot>MAX_OP_REGISTERED) { wmOperator *opt= wm->operators.first; BLI_remlink(&wm->operators, opt); - wm_operator_free(opt); + WM_operator_free(opt); tot--; } } @@ -144,7 +144,7 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm) while((op= wm->operators.first)) { BLI_remlink(&wm->operators, op); - wm_operator_free(op); + WM_operator_free(op); } while((km= wm->keymaps.first)) { diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index d1047ca4e63..1342ebf78b9 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -277,6 +277,22 @@ void wm_draw_update(bContext *C) /* ********************* operators ******************* */ +/* for running operators with frozen context (modal handlers, menus) */ +int WM_operator_call(bContext *C, wmOperator *op) +{ + int retval= OPERATOR_CANCELLED; + + if(op->type->exec) + retval= op->type->exec(C, op); + + if((retval & OPERATOR_FINISHED) && (op->type->flag & OPTYPE_REGISTER)) { + wm_operator_register(CTX_wm_manager(C), op); + } + else + WM_operator_free(op); + + return retval; +} static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, IDProperty *properties) { @@ -284,7 +300,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, I int retval= OPERATOR_PASS_THROUGH; if(ot->poll==NULL || ot->poll(C)) { - wmOperator *op= MEM_callocN(sizeof(wmOperator), "wmOperator"); + wmOperator *op= MEM_callocN(sizeof(wmOperator), ot->idname); /* XXX operatortype names are static still. for debug */ if(properties) op->properties= IDP_CopyProperty(properties); @@ -305,7 +321,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, I wm_operator_register(wm, op); } else if(!(retval & OPERATOR_RUNNING_MODAL)) { - wm_operator_free(op); + WM_operator_free(op); } } @@ -313,7 +329,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, I } /* invokes operator in context */ -int WM_operator_call(bContext *C, const char *opstring, int context, IDProperty *properties) +int WM_operator_name_call(bContext *C, const char *opstring, int context, IDProperty *properties) { wmOperatorType *ot= WM_operatortype_find(opstring); wmWindow *window= CTX_wm_window(C); @@ -404,7 +420,7 @@ void WM_event_remove_handlers(bContext *C, ListBase *handlers) CTX_wm_region_set(C, region); } - wm_operator_free(handler->op); + WM_operator_free(handler->op); } else if(handler->ui_remove) { ScrArea *area= CTX_wm_area(C); @@ -498,7 +514,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand handler->op= NULL; } else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) { - wm_operator_free(op); + WM_operator_free(op); handler->op= NULL; } diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index dc53bff290d..22616a49af1 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -167,7 +167,6 @@ ListBase *WM_keymap_listbase(wmWindowManager *wm, const char *nameid, int spacei BLI_strncpy(km->nameid, nameid, KMAP_MAX_NAME); km->spaceid= spaceid; km->regionid= regionid; - printf("added keymap %s %d %d\n", nameid, spaceid, regionid); BLI_addtail(&wm->keymaps, km); } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 56909b425d2..b8b7f8fadaa 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -103,8 +103,10 @@ static void operator_callback(bContext *C, void *arg, int retval) if(op && retval > 0) op->type->exec(C, op); + } +/* call anywhere */ void WM_error(bContext *C, char *str) { char buf[148], testbuf[128]; @@ -115,16 +117,18 @@ void WM_error(bContext *C, char *str) } +/* op->invoke */ int WM_operator_confirm(bContext *C, wmOperator *op, wmEvent *event) { char buf[512]; sprintf(buf, "OK? %%i%d%%t|%s", ICON_HELP, op->type->name); - uiPupmenu(C, 0, operator_callback, op, buf); + uiPupmenuOperator(C, 0, op, NULL, buf); - return 1; + return OPERATOR_RUNNING_MODAL; } +/* op->poll */ int WM_operator_winactive(bContext *C) { if(CTX_wm_window(C)==NULL) return 0; @@ -177,8 +181,9 @@ static void recent_filelist(char *pup) } } -static void recentfile_callback(bContext *C, void *arg, int event) +static int recentfile_exec(bContext *C, wmOperator *op) { + int event= RNA_enum_get(op->ptr, "nr"); if(event>0) { if (G.sce[0] && (event==1)) @@ -190,6 +195,7 @@ static void recentfile_callback(bContext *C, void *arg, int event) } } } + return 0; } static int wm_recentfile_invoke(bContext *C, wmOperator *op, wmEvent *event) @@ -197,9 +203,9 @@ static int wm_recentfile_invoke(bContext *C, wmOperator *op, wmEvent *event) char pup[2048]; recent_filelist(pup); - uiPupmenu(C, 0, recentfile_callback, op, pup); + uiPupmenuOperator(C, 0, op, "nr", pup); - return 1; + return OPERATOR_RUNNING_MODAL; } static void WM_OT_open_recentfile(wmOperatorType *ot) @@ -208,9 +214,13 @@ static void WM_OT_open_recentfile(wmOperatorType *ot) ot->idname= "WM_OT_open_recentfile"; ot->invoke= wm_recentfile_invoke; + ot->exec= recentfile_exec; ot->poll= WM_operator_winactive; ot->flag= OPTYPE_REGISTER; + + RNA_def_property(ot->srna, "nr", PROP_ENUM, PROP_NONE); + } /* *********************** */ diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h index 139c360dfda..2dd4acd9be2 100644 --- a/source/blender/windowmanager/wm.h +++ b/source/blender/windowmanager/wm.h @@ -36,7 +36,6 @@ extern void wm_close_and_free_all(bContext *C, ListBase *); extern void wm_add_default(bContext *C); extern void wm_check(bContext *C); -void wm_operator_free(wmOperator *op); /* register to windowmanager for redo or macro */ void wm_operator_register(wmWindowManager *wm, wmOperator *op);