cda4d27eb9861e631510f59a3b6aa5cafc22f2c1 source/blender/editors/transform/transform.c | 191 +++++++++++--------- source/blender/editors/transform/transform.h | 2 +- source/blender/editors/transform/transform_ops.c | 2 +- source/blender/makesdna/DNA_windowmanager_types.h | 4 +- source/blender/windowmanager/WM_types.h | 1 + .../blender/windowmanager/intern/wm_event_system.c | 55 ++++-- 6 files changed, 155 insertions(+), 100 deletions(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 41e7356..416a068 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -74,9 +74,12 @@ #include "ED_mesh.h" #include "ED_clip.h" +#include "PIL_time.h" + #include "UI_view2d.h" #include "WM_types.h" #include "WM_api.h" +#include "wm_event_system.h" #include "BLI_math.h" #include "BLI_blenlib.h" @@ -532,10 +535,6 @@ wmKeyMap* transform_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM); WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM); - WM_modalkeymap_add_item(keymap, GKEY, KM_PRESS, 0, 0, TFM_MODAL_TRANSLATE); - WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, TFM_MODAL_ROTATE); - WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, 0, 0, TFM_MODAL_RESIZE); - WM_modalkeymap_add_item(keymap, TABKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_SNAP_TOGGLE); WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_SNAP_INV_ON); @@ -560,8 +559,43 @@ wmKeyMap* transform_modal_keymap(wmKeyConfig *keyconf) return keymap; } +int is_same_type(int type1, int type2) +{ + if(type1 == type2) + return 1; + + switch(type1) { + case SELECTMOUSE: + if(U.flag & USER_LMOUSESELECT) + return type2 == LEFTMOUSE; + else + return type2 == RIGHTMOUSE; + + case ACTIONMOUSE: + if(U.flag & USER_LMOUSESELECT) + return type2 == RIGHTMOUSE; + else + return type2 == LEFTMOUSE; + } + + switch(type2) { + case SELECTMOUSE: + if(U.flag & USER_LMOUSESELECT) + return type1 == LEFTMOUSE; + else + return type1 == RIGHTMOUSE; + + case ACTIONMOUSE: + if(U.flag & USER_LMOUSESELECT) + return type1 == RIGHTMOUSE; + else + return type1 == LEFTMOUSE; + } -int transformEvent(TransInfo *t, wmEvent *event) + return 0; +} + +int transformEvent(TransInfo *t, wmOperator *op, wmEvent *event) { float mati[3][3]= MAT3_UNITY; char cmode = constraintModeToChar(t); @@ -590,8 +624,12 @@ int transformEvent(TransInfo *t, wmEvent *event) t->redraw |= handleSnapping(t, event); } - /* handle modal keymap first */ - if (event->type == EVT_MODAL_MAP) { + if (op->kmi && strcmp(op->idname, op->kmi->idname) == 0 && is_same_type(op->kmi->type, event->type) && op->kmi->val == event->val && + op->kmi->alt == event->alt && op->kmi->ctrl == event->ctrl && op->kmi->shift == event->shift && op->kmi->oskey == event->oskey) { + // If this button was the button that created this operator being pressed again then it is a confirm. + t->state = TRANS_CONFIRM; + } + else if (event->type == EVT_MODAL_MAP) { switch (event->val) { case TFM_MODAL_CANCEL: t->state = TRANS_CANCEL; @@ -599,55 +637,6 @@ int transformEvent(TransInfo *t, wmEvent *event) case TFM_MODAL_CONFIRM: t->state = TRANS_CONFIRM; break; - case TFM_MODAL_TRANSLATE: - /* only switch when... */ - if( ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) { - resetTransRestrictions(t); - restoreTransObjects(t); - initTranslation(t); - initSnapping(t, NULL); // need to reinit after mode change - t->redraw |= TREDRAW_HARD; - } - else if(t->mode == TFM_TRANSLATION) { - if(t->options&CTX_MOVIECLIP) { - restoreTransObjects(t); - - t->flag^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - } - } - break; - case TFM_MODAL_ROTATE: - /* only switch when... */ - if(!(t->options & CTX_TEXTURE) && !(t->options & CTX_MOVIECLIP)) { - if( ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) { - - resetTransRestrictions(t); - - if (t->mode == TFM_ROTATION) { - restoreTransObjects(t); - initTrackball(t); - } - else { - restoreTransObjects(t); - initRotation(t); - } - initSnapping(t, NULL); // need to reinit after mode change - t->redraw |= TREDRAW_HARD; - } - } - break; - case TFM_MODAL_RESIZE: - /* only switch when... */ - if( ELEM3(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) { - resetTransRestrictions(t); - restoreTransObjects(t); - initResize(t); - initSnapping(t, NULL); // need to reinit after mode change - t->redraw |= TREDRAW_HARD; - } - break; - case TFM_MODAL_SNAP_INV_ON: t->modifiers |= MOD_SNAP_INVERT; t->redraw |= TREDRAW_HARD; @@ -861,6 +850,16 @@ int transformEvent(TransInfo *t, wmEvent *event) initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; } + else if(t->mode == TFM_TRANSLATION) { + if(t->options&CTX_MOVIECLIP) { + restoreTransObjects(t); + + t->flag^= T_ALT_TRANSFORM; + t->redraw |= TREDRAW_HARD; + } + else + t->state = TRANS_CONFIRM; + } break; case SKEY: /* only switch when... */ @@ -871,14 +870,16 @@ int transformEvent(TransInfo *t, wmEvent *event) initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; } + else if(t->mode == TFM_RESIZE) + t->state = TRANS_CONFIRM; break; case RKEY: /* only switch when... */ if(!(t->options & CTX_TEXTURE) && !(t->options & CTX_MOVIECLIP)) { - if( ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) { - + if( ELEM(t->mode, TFM_RESIZE, TFM_TRANSLATION) ) { + resetTransRestrictions(t); - + if (t->mode == TFM_ROTATION) { restoreTransObjects(t); initTrackball(t); @@ -890,6 +891,25 @@ int transformEvent(TransInfo *t, wmEvent *event) initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; } + else if( ELEM(t->mode, TFM_ROTATION, TFM_TRACKBALL) ) { + if ( event->shift ) { + resetTransRestrictions(t); + + if (t->mode == TFM_ROTATION) { + restoreTransObjects(t); + initTrackball(t); + } + else { + restoreTransObjects(t); + initRotation(t); + } + initSnapping(t, NULL); // need to reinit after mode change + t->redraw |= TREDRAW_HARD; + } + else { + t->state = TRANS_CONFIRM; + } + } } break; case CKEY: @@ -1035,30 +1055,39 @@ int transformEvent(TransInfo *t, wmEvent *event) } else if (event->val==KM_RELEASE) { - switch (event->type){ - case LEFTSHIFTKEY: - case RIGHTSHIFTKEY: - t->modifiers &= ~MOD_CONSTRAINT_PLANE; - t->redraw |= TREDRAW_HARD; - break; - - case MIDDLEMOUSE: - if ((t->flag & T_NO_CONSTRAINT)==0) { - t->modifiers &= ~MOD_CONSTRAINT_SELECT; - postSelectConstraint(t); + if (op->kmi && strcmp(op->idname, op->kmi->idname) == 0 && is_same_type(op->kmi->type, event->type) && is_same_type(event->prevtype, event->type) && + op->kmi->alt == event->alt && op->kmi->ctrl == event->ctrl && op->kmi->shift == event->shift && op->kmi->oskey == event->oskey) { + // If this is the same key that was originally pressed to begin this operator, and it is now being released, + // then this may be a drag. If the mouse has moved far or long enough, we are at the end of the drag. + if (PIL_check_seconds_timer() - event->prevkeytime > 0.250 || ABS(event->mval[0] - t->imval[0]) > 10 || ABS(event->mval[1] - t->imval[1]) > 10) + t->state = TRANS_CONFIRM; + } + else { + switch (event->type){ + case LEFTSHIFTKEY: + case RIGHTSHIFTKEY: + t->modifiers &= ~MOD_CONSTRAINT_PLANE; t->redraw |= TREDRAW_HARD; + break; + + case MIDDLEMOUSE: + if ((t->flag & T_NO_CONSTRAINT)==0) { + t->modifiers &= ~MOD_CONSTRAINT_SELECT; + postSelectConstraint(t); + t->redraw |= TREDRAW_HARD; + } + break; + // case LEFTMOUSE: + // case RIGHTMOUSE: + // if(WM_modal_tweak_exit(event, t->event_type)) + //// if (t->options & CTX_TWEAK) + // t->state = TRANS_CONFIRM; + // break; + default: + handled = 0; + break; + } } - break; -// case LEFTMOUSE: -// case RIGHTMOUSE: -// if(WM_modal_tweak_exit(event, t->event_type)) -//// if (t->options & CTX_TWEAK) -// t->state = TRANS_CONFIRM; -// break; - default: - handled = 0; - break; - } /* confirm transform if launch key is released after mouse move */ if (t->flag & T_RELEASE_CONFIRM) diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index aab7dda..a2e181d 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -435,7 +435,7 @@ void TRANSFORM_OT_transform(struct wmOperatorType *ot); int initTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op, struct wmEvent *event, int mode); void saveTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op); -int transformEvent(TransInfo *t, struct wmEvent *event); +int transformEvent(TransInfo *t, struct wmOperator *op, struct wmEvent *event); void transformApply(struct bContext *C, TransInfo *t); int transformEnd(struct bContext *C, TransInfo *t); diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 1843768..c637482 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -369,7 +369,7 @@ static int transform_modal(bContext *C, wmOperator *op, wmEvent *event) /* XXX insert keys are called here, and require context */ t->context= C; - exit_code = transformEvent(t, event); + exit_code = transformEvent(t, op, event); t->context= NULL; transformApply(C, t); diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 156d2eb..15b1683 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -306,6 +306,8 @@ typedef struct wmOperator { IDProperty *properties; /* saved, user-settable properties */ /* runtime */ + struct wmEventHandler *handler;/* The event handler that created this operator, if any */ + struct wmKeyMapItem *kmi; /* The key that was pressed to create this operator, if any */ struct wmOperatorType *type;/* operator type definition from idname */ void *customdata; /* custom storage, only while operator runs */ void *py_instance; /* python stores the class instance here */ @@ -316,7 +318,7 @@ typedef struct wmOperator { ListBase macro; /* list of operators, can be a tree */ struct wmOperator *opm; /* current running macro, not saved */ struct uiLayout *layout; /* runtime for drawing */ - short flag, pad[3]; + short flag, keydown, pad[2]; } wmOperator; diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 758cf7b..3e8c0ee 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -357,6 +357,7 @@ typedef struct wmEvent { short prevval; int prevx, prevy; double prevclicktime; + double prevkeytime; int prevclickx, prevclicky; /* modifier states */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 079833f..b384267 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -629,14 +629,21 @@ int WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op) return op->type->exec != NULL; } -static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, PointerRNA *properties, ReportList *reports) +static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, wmEventHandler *handler, wmKeyMapItem *kmi, PointerRNA *properties, ReportList *reports) { wmOperator *op= MEM_callocN(sizeof(wmOperator), ot->idname); /* XXX operatortype names are static still. for debug */ /* XXX adding new operator could be function, only happens here now */ op->type= ot; BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME); - + + op->handler= handler; + op->kmi= kmi; + + // If it was a button that created this operator then the key must be down. + // Otherwise it's a python script or something and the key doesn't exist. + op->keydown= !!kmi; + /* initialize properties, either copy or create */ op->ptr= MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA"); if(properties && properties->data) { @@ -684,7 +691,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, P { wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0); PointerRNA someptr = RNA_property_pointer_get(properties, prop); - wmOperator *opm= wm_operator_create(wm, otm, &someptr, NULL); + wmOperator *opm= wm_operator_create(wm, otm, handler, kmi, &someptr, NULL); IDP_ReplaceGroupInGroup(opm->properties, otmacro->properties); @@ -698,7 +705,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, P } else { 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); + wmOperator *opm= wm_operator_create(wm, otm, handler, kmi, otmacro->ptr, NULL); BLI_addtail(&motherop->macro, opm); opm->opm= motherop; /* pointer to mom, for modal() */ @@ -770,7 +777,7 @@ static int wm_operator_init_from_last(wmWindowManager *wm, wmOperator *op) return change; } -static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports, short poll_only) +static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEventHandler *handler, wmKeyMapItem *kmi, wmEvent *event, PointerRNA *properties, ReportList *reports, short poll_only) { wmWindowManager *wm= CTX_wm_manager(C); int retval= OPERATOR_PASS_THROUGH; @@ -780,7 +787,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P return WM_operator_poll(C, ot); if(WM_operator_poll(C, ot)) { - wmOperator *op= wm_operator_create(wm, ot, properties, reports); /* if reports==NULL, theyll be initialized */ + wmOperator *op= wm_operator_create(wm, ot, handler, kmi, properties, reports); /* if reports==NULL, theyll be initialized */ /* initialize setting from previous run */ if(wm->op_undo_depth == 0 && (ot->flag & OPTYPE_REGISTER)) { /* not called by py script */ @@ -954,7 +961,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA CTX_wm_region_set(C, ar1); } - retval= wm_operator_invoke(C, ot, event, properties, reports, poll_only); + retval= wm_operator_invoke(C, ot, NULL, NULL, event, properties, reports, poll_only); /* set region back */ CTX_wm_region_set(C, ar); @@ -968,7 +975,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA ARegion *ar= CTX_wm_region(C); CTX_wm_region_set(C, NULL); - retval= wm_operator_invoke(C, ot, event, properties, reports, poll_only); + retval= wm_operator_invoke(C, ot, NULL, NULL, event, properties, reports, poll_only); CTX_wm_region_set(C, ar); return retval; @@ -982,7 +989,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA CTX_wm_region_set(C, NULL); CTX_wm_area_set(C, NULL); - retval= wm_operator_invoke(C, ot, event, properties, reports, poll_only); + retval= wm_operator_invoke(C, ot, NULL, NULL, event, properties, reports, poll_only); CTX_wm_area_set(C, area); CTX_wm_region_set(C, ar); @@ -990,7 +997,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA } case WM_OP_EXEC_DEFAULT: case WM_OP_INVOKE_DEFAULT: - return wm_operator_invoke(C, ot, event, properties, reports, poll_only); + return wm_operator_invoke(C, ot, NULL, NULL, event, properties, reports, poll_only); } } @@ -1019,7 +1026,7 @@ int WM_operator_call_py(bContext *C, wmOperatorType *ot, int context, PointerRNA #if 0 wmOperator *op; - op= wm_operator_create(wm, ot, properties, reports); + op= wm_operator_create(wm, ot, NULL, NULL, properties, reports); if (op->type->exec) { if(op->type->flag & OPTYPE_UNDO) @@ -1290,7 +1297,7 @@ static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *eve } /* Warning: this function removes a modal handler, when finished */ -static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties) +static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmKeyMapItem *kmi, wmEvent *event, PointerRNA *properties) { int retval= OPERATOR_PASS_THROUGH; @@ -1299,6 +1306,20 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand wmOperator *op= handler->op; wmOperatorType *ot= op->type; + if(op->kmi) { + if (op->kmi->type==event->type && op->kmi->alt==event->alt && op->kmi->ctrl==event->ctrl && op->kmi->shift==event->shift && op->kmi->oskey==event->oskey) { + // If this is the same button as that created the operator and it's a duplicate message, don't pass it along. + if (event->val==KM_PRESS && op->keydown) + return (WM_HANDLER_BREAK|WM_HANDLER_MODAL); + + if (event->val==KM_PRESS && !op->keydown) + op->keydown = 1; + + if (event->val==KM_RELEASE && op->keydown) + op->keydown = 0; + } + } + if(ot->modal) { /* we set context to where modal handler came from */ wmWindowManager *wm= CTX_wm_manager(C); @@ -1366,7 +1387,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand wmOperatorType *ot= WM_operatortype_find(event->keymap_idname, 0); if(ot) - retval= wm_operator_invoke(C, ot, event, properties, NULL, FALSE); + retval= wm_operator_invoke(C, ot, handler, kmi, event, properties, NULL, FALSE); } /* Finished and pass through flag as handled */ @@ -1611,7 +1632,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) event->keymap_idname= kmi->idname; /* weak, but allows interactive callback to not use rawkey */ - action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr); + action |= wm_handler_operator_call(C, handlers, handler, kmi, event, kmi->ptr); if(action & WM_HANDLER_BREAK) /* not always_pass here, it denotes removed handler */ break; } @@ -1661,7 +1682,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) } else { /* modal, swallows all */ - action |= wm_handler_operator_call(C, handlers, handler, event, NULL); + action |= wm_handler_operator_call(C, handlers, handler, NULL, event, NULL); } if(action & WM_HANDLER_BREAK) { @@ -2043,10 +2064,12 @@ void wm_event_do_handlers(bContext *C) win->eventstate->prevclickx = event->x; win->eventstate->prevclicky = event->y; } else { /* reset if not */ - win->eventstate->prevtype = -1; + win->eventstate->prevtype = event->type; win->eventstate->prevval = 0; win->eventstate->prevclicktime = 0; } + + win->eventstate->prevkeytime = (event->val == KM_PRESS || event->val == KM_RELEASE)?PIL_check_seconds_timer():0; } /* unlink and free here, blender-quit then frees all */